Skip to content

Commit 3978097

Browse files
author
Stefanos Kornilios Mitsis Poiitidis
authored
Merge pull request #705 from FEX-Emu/skmp/mmap-cache-flushing
Flush IR/Code cache on mmap, mmunmap & mprot
2 parents e95d1bd + 613e5b6 commit 3978097

File tree

13 files changed

+100
-33
lines changed

13 files changed

+100
-33
lines changed

External/FEXCore/Source/Interface/Config/Config.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ namespace FEXCore::Config {
3434
CTX->Config.TSOEnabled = Config != 0;
3535
break;
3636
case FEXCore::Config::CONFIG_SMC_CHECKS:
37-
CTX->Config.SMCChecks = Config != 0;
37+
CTX->Config.SMCChecks = static_cast<FEXCore::Config::ConfigSMCChecks>(Config);
3838
break;
3939
case FEXCore::Config::CONFIG_ABI_LOCAL_FLAGS:
4040
CTX->Config.ABILocalFlags = Config != 0;

External/FEXCore/Source/Interface/Context/Context.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ namespace FEXCore::Context {
6868

6969
bool Is64BitMode {true};
7070
bool TSOEnabled {true};
71-
bool SMCChecks {false};
71+
FEXCore::Config::ConfigSMCChecks SMCChecks {FEXCore::Config::CONFIG_SMC_MMAN};
7272
bool ABILocalFlags {false};
7373
bool ABINoPF {false};
7474

@@ -209,7 +209,7 @@ namespace FEXCore::Context {
209209
void ExecutionThread(FEXCore::Core::InternalThreadState *Thread);
210210
void NotifyPause();
211211

212-
void AddBlockMapping(FEXCore::Core::InternalThreadState *Thread, uint64_t Address, void *Ptr);
212+
void AddBlockMapping(FEXCore::Core::InternalThreadState *Thread, uint64_t Address, void *Ptr, uint64_t Start, uint64_t Length);
213213

214214
FEXCore::CodeLoader *LocalLoader{};
215215

External/FEXCore/Source/Interface/Core/Core.cpp

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -607,8 +607,8 @@ namespace FEXCore::Context {
607607
return Thread;
608608
}
609609

610-
void Context::AddBlockMapping(FEXCore::Core::InternalThreadState *Thread, uint64_t Address, void *Ptr) {
611-
Thread->LookupCache->AddBlockMapping(Address, Ptr);
610+
void Context::AddBlockMapping(FEXCore::Core::InternalThreadState *Thread, uint64_t Address, void *Ptr, uint64_t Start, uint64_t Length) {
611+
Thread->LookupCache->AddBlockMapping(Address, Ptr, Start, Length);
612612
}
613613

614614
void Context::ClearCodeCache(FEXCore::Core::InternalThreadState *Thread, bool AlsoClearIRCache) {
@@ -670,7 +670,7 @@ namespace FEXCore::Context {
670670
TableInfo = Block.DecodedInstructions[i].TableInfo;
671671
DecodedInfo = &Block.DecodedInstructions[i];
672672

673-
if (Config.SMCChecks) {
673+
if (Config.SMCChecks == FEXCore::Config::CONFIG_SMC_FULL) {
674674
auto ExistingCodePtr = reinterpret_cast<uint64_t*>(Block.Entry + BlockInstructionsLength);
675675

676676
auto CodeChanged = Thread->OpDispatcher->_ValidateCode(ExistingCodePtr[0], ExistingCodePtr[1], (uintptr_t)ExistingCodePtr - GuestRIP, DecodedInfo->InstSize);
@@ -853,7 +853,8 @@ namespace FEXCore::Context {
853853

854854
if (AOTEntry != Mod->end()) {
855855
// verify hash
856-
auto hash = fasthash64((void*)(AOTEntry->second.start + file->second.Start - file->second.Offset), AOTEntry->second.len, 0);
856+
auto MappedStart = AOTEntry->second.start + file->second.Start - file->second.Offset;
857+
auto hash = fasthash64((void*)MappedStart, AOTEntry->second.len, 0);
857858
if (hash == AOTEntry->second.crc) {
858859
IRList = AOTEntry->second.IR;
859860
//LogMan::Msg::D("using %s + %lx -> %lx\n", file->second.fileid.c_str(), AOTEntry->first, GuestRIP);
@@ -862,7 +863,7 @@ namespace FEXCore::Context {
862863

863864
RAData = AOTEntry->second.RAData;
864865
DebugData = new FEXCore::Core::DebugData();
865-
StartAddr = AOTEntry->second.start;
866+
StartAddr = MappedStart;
866867
Length = AOTEntry->second.len;
867868

868869
GeneratedIR = true;
@@ -1117,7 +1118,7 @@ namespace FEXCore::Context {
11171118
--Thread->CompileBlockReentrantRefCount;
11181119

11191120
// Insert to lookup cache
1120-
AddBlockMapping(Thread, GuestRIP, CodePtr);
1121+
AddBlockMapping(Thread, GuestRIP, CodePtr, StartAddr, Length);
11211122

11221123
return (uintptr_t)CodePtr;
11231124

@@ -1177,6 +1178,20 @@ namespace FEXCore::Context {
11771178
SignalDelegation->UninstallTLSState(Thread);
11781179
}
11791180

1181+
void FlushCodeRange(FEXCore::Core::InternalThreadState *Thread, uint64_t Start, uint64_t Length) {
1182+
1183+
if (Thread->CTX->Config.SMCChecks == FEXCore::Config::CONFIG_SMC_MMAN) {
1184+
auto lower = Thread->LookupCache->CodePages.lower_bound(Start >> 12);
1185+
auto upper = Thread->LookupCache->CodePages.upper_bound((Start + Length) >> 12);
1186+
1187+
for (auto it = lower; it != upper; it++) {
1188+
for (auto Address: it->second)
1189+
Context::RemoveCodeEntry(Thread, Address);
1190+
it->second.clear();
1191+
}
1192+
}
1193+
}
1194+
11801195
void Context::RemoveCodeEntry(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestRIP) {
11811196
Thread->LocalIRCache.erase(GuestRIP);
11821197
Thread->LookupCache->Erase(GuestRIP);
@@ -1248,7 +1263,7 @@ namespace FEXCore::Context {
12481263
auto fileid = base_filename + "-" + std::to_string(filename_hash) + "-";
12491264

12501265
// append optimization flags to the fileid
1251-
fileid += Config.SMCChecks ? "S" : "s";
1266+
fileid += (Config.SMCChecks == FEXCore::Config::CONFIG_SMC_FULL) ? "S" : "s";
12521267
fileid += Config.TSOEnabled ? "T" : "t";
12531268
fileid += Config.ABILocalFlags ? "L" : "l";
12541269
fileid += Config.ABINoPF ? "p" : "P";

External/FEXCore/Source/Interface/Core/LookupCache.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,16 @@ class LookupCache {
3535
}
3636
}
3737

38-
void AddBlockMapping(uint64_t Address, void *HostCode) {
38+
std::map<uint64_t, std::vector<uint64_t>> CodePages;
39+
40+
void AddBlockMapping(uint64_t Address, void *HostCode, uint64_t Start, uint64_t Length) {
3941
auto InsertPoint = BlockList.emplace(Address, (uintptr_t)HostCode);
4042
LogMan::Throw::A(InsertPoint.second == true, "Dupplicate block mapping added");
4143

44+
for (auto CurrentPage = Start >> 12, EndPage = (Start + Length) >> 12; CurrentPage <= EndPage; CurrentPage++) {
45+
CodePages[CurrentPage].push_back(Address);
46+
}
47+
4248
// no need to update L1 or L2, they will get updated on first lookup
4349
}
4450

@@ -197,6 +203,7 @@ class LookupCache {
197203
}
198204
};
199205

206+
200207
std::map<BlockLinkTag, std::function<void()>> BlockLinks;
201208
std::map<uint64_t, uint64_t> BlockList;
202209

External/FEXCore/include/FEXCore/Config/Config.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@ namespace FEXCore::Config {
4444
CONFIG_CUSTOM,
4545
};
4646

47+
enum ConfigSMCChecks {
48+
CONFIG_SMC_NONE,
49+
CONFIG_SMC_MMAN,
50+
CONFIG_SMC_FULL,
51+
};
52+
4753
void SetConfig(FEXCore::Context::Context *CTX, ConfigOption Option, uint64_t Config);
4854
void SetConfig(FEXCore::Context::Context *CTX, ConfigOption Option, std::string const &Config);
4955
uint64_t GetConfig(FEXCore::Context::Context *CTX, ConfigOption Option);

External/FEXCore/include/FEXCore/Core/Context.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,4 +238,5 @@ namespace FEXCore::Context {
238238
void RemoveNamedRegion(FEXCore::Context::Context *CTX, uintptr_t Base, uintptr_t Length);
239239
void SetAOTIRLoader(FEXCore::Context::Context *CTX, std::function<std::unique_ptr<std::istream>(const std::string&)> CacheReader);
240240
bool WriteAOTIR(FEXCore::Context::Context *CTX, std::function<std::unique_ptr<std::ostream>(const std::string&)> CacheWriter);
241+
void FlushCodeRange(FEXCore::Core::InternalThreadState *Thread, uint64_t Start, uint64_t Length);
241242
}

Source/Common/ArgumentLoader.cpp

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,11 @@ namespace FEX::ArgLoader {
6666
.help("Number of physical hardware threads to tell the process we have")
6767
.set_default(1);
6868

69-
CPUGroup.add_option("--smc-full-checks")
69+
CPUGroup.add_option("--smc-checks")
7070
.dest("SMCChecks")
71-
.action("store_true")
72-
.help("Checks code for modification before execution. Slow.")
73-
.set_default(false);
71+
.choices({"none", "mman", "full"})
72+
.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)")
73+
.set_default("mman");
7474

7575
CPUGroup.add_option("--unsafe-no-tso")
7676
.dest("TSOEnabled")
@@ -229,8 +229,13 @@ namespace FEX::ArgLoader {
229229
}
230230

231231
if (Options.is_set_by_user("SMCChecks")) {
232-
bool SMCChecks = Options.get("SMCChecks");
233-
Set(FEXCore::Config::ConfigOption::CONFIG_SMC_CHECKS, std::to_string(SMCChecks));
232+
auto SMCChecks = Options["SMCChecks"];
233+
if (SMCChecks == "none")
234+
Set(FEXCore::Config::ConfigOption::CONFIG_SMC_CHECKS, "0");
235+
else if (SMCChecks == "mman")
236+
Set(FEXCore::Config::ConfigOption::CONFIG_SMC_CHECKS, "1");
237+
else if (SMCChecks == "full")
238+
Set(FEXCore::Config::ConfigOption::CONFIG_SMC_CHECKS, "2");
234239
}
235240
if (Options.is_set_by_user("AbiLocalFlags")) {
236241
bool AbiLocalFlags = Options.get("AbiLocalFlags");

Source/Tests/ELFLoader.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ int main(int argc, char **argv, char **const envp) {
205205
FEXCore::Config::Value<std::string> OutputLog{FEXCore::Config::CONFIG_OUTPUTLOG, "stderr"};
206206
FEXCore::Config::Value<std::string> DumpIR{FEXCore::Config::CONFIG_DUMPIR, "no"};
207207
FEXCore::Config::Value<bool> TSOEnabledConfig{FEXCore::Config::CONFIG_TSO_ENABLED, true};
208-
FEXCore::Config::Value<bool> SMCChecksConfig{FEXCore::Config::CONFIG_SMC_CHECKS, false};
208+
FEXCore::Config::Value<uint8_t> SMCChecksConfig{FEXCore::Config::CONFIG_SMC_CHECKS, FEXCore::Config::CONFIG_SMC_MMAN};
209209
FEXCore::Config::Value<bool> ABILocalFlags{FEXCore::Config::CONFIG_ABI_LOCAL_FLAGS, false};
210210
FEXCore::Config::Value<bool> AbiNoPF{FEXCore::Config::CONFIG_ABI_NO_PF, false};
211211
FEXCore::Config::Value<bool> AOTIRCapture{FEXCore::Config::CONFIG_AOTIR_GENERATE, false};

Source/Tests/LinuxSyscalls/x32/Memory.cpp

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,13 @@ namespace FEX::HLE::x32 {
2424
auto Result = (uint64_t)static_cast<FEX::HLE::x32::x32SyscallHandler*>(FEX::HLE::_SyscallHandler)->GetAllocator()->
2525
mmap(reinterpret_cast<void*>(addr), length, prot,flags, fd, offset);
2626

27-
if (Result != -1 && !(flags & MAP_ANONYMOUS)) {
28-
auto filename = get_fdpath(fd);
27+
if (Result != -1) {
28+
if (!(flags & MAP_ANONYMOUS)) {
29+
auto filename = get_fdpath(fd);
2930

30-
FEXCore::Context::AddNamedRegion(Thread->CTX, Result, length, offset, filename);
31+
FEXCore::Context::AddNamedRegion(Thread->CTX, Result, length, offset, filename);
32+
}
33+
FEXCore::Context::FlushCodeRange(Thread, (uintptr_t)Result, length);
3134
}
3235

3336
return Result;
@@ -37,10 +40,13 @@ namespace FEX::HLE::x32 {
3740
auto Result = (uint64_t)static_cast<FEX::HLE::x32::x32SyscallHandler*>(FEX::HLE::_SyscallHandler)->GetAllocator()->
3841
mmap(reinterpret_cast<void*>(addr), length, prot,flags, fd, (uint64_t)pgoffset * 0x1000);
3942

40-
if (Result != -1 && !(flags & MAP_ANONYMOUS)) {
41-
auto filename = get_fdpath(fd);
43+
if (Result != -1) {
44+
if (!(flags & MAP_ANONYMOUS)) {
45+
auto filename = get_fdpath(fd);
4246

43-
FEXCore::Context::AddNamedRegion(Thread->CTX, Result, length, pgoffset * 0x1000, filename);
47+
FEXCore::Context::AddNamedRegion(Thread->CTX, Result, length, pgoffset * 0x1000, filename);
48+
}
49+
FEXCore::Context::FlushCodeRange(Thread, (uintptr_t)Result, length);
4450
}
4551

4652
return Result;
@@ -51,12 +57,16 @@ namespace FEX::HLE::x32 {
5157
munmap(addr, length);
5258
if (Result != -1) {
5359
FEXCore::Context::RemoveNamedRegion(Thread->CTX, (uintptr_t)addr, length);
60+
FEXCore::Context::FlushCodeRange(Thread, (uintptr_t)addr, length);
5461
}
5562
return Result;
5663
});
5764

5865
REGISTER_SYSCALL_IMPL_X32(mprotect, [](FEXCore::Core::InternalThreadState *Thread, void *addr, uint32_t len, int prot) -> uint64_t {
5966
uint64_t Result = ::mprotect(addr, len, prot);
67+
if (Result != -1 && prot & PROT_EXEC) {
68+
FEXCore::Context::FlushCodeRange(Thread, (uintptr_t)addr, len);
69+
}
6070
SYSCALL_ERRNO();
6171
});
6272

Source/Tests/LinuxSyscalls/x64/Memory.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,21 @@ namespace FEX::HLE::x64 {
2525
uint64_t Result = ::munmap(addr, length);
2626
if (Result != -1) {
2727
FEXCore::Context::RemoveNamedRegion(Thread->CTX, (uintptr_t)addr, length);
28+
FEXCore::Context::FlushCodeRange(Thread, (uintptr_t)addr, length);
2829
}
2930
SYSCALL_ERRNO();
3031
});
3132

3233
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 {
3334
static FEXCore::Config::Value<bool> AOTIRLoad(FEXCore::Config::CONFIG_AOTIR_LOAD, false);
3435
uint64_t Result = reinterpret_cast<uint64_t>(::mmap(addr, length, prot, flags, fd, offset));
35-
if (Result != -1 && !(flags & MAP_ANONYMOUS)) {
36-
auto filename = get_fdpath(fd);
36+
if (Result != -1) {
37+
if (!(flags & MAP_ANONYMOUS)) {
38+
auto filename = get_fdpath(fd);
3739

38-
FEXCore::Context::AddNamedRegion(Thread->CTX, Result, length, offset, filename);
40+
FEXCore::Context::AddNamedRegion(Thread->CTX, Result, length, offset, filename);
41+
}
42+
FEXCore::Context::FlushCodeRange(Thread, (uintptr_t)Result, length);
3943
}
4044
SYSCALL_ERRNO();
4145
});
@@ -47,6 +51,9 @@ namespace FEX::HLE::x64 {
4751

4852
REGISTER_SYSCALL_IMPL_X64(mprotect, [](FEXCore::Core::InternalThreadState *Thread, void *addr, size_t len, int prot) -> uint64_t {
4953
uint64_t Result = ::mprotect(addr, len, prot);
54+
if (Result != -1 && prot & PROT_EXEC) {
55+
FEXCore::Context::FlushCodeRange(Thread, (uintptr_t)addr, len);
56+
}
5057
SYSCALL_ERRNO();
5158
});
5259

Source/Tests/TestHarnessRunner.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ int main(int argc, char **argv, char **const envp) {
7171
FEXCore::Config::Value<std::string> OutputLog{FEXCore::Config::CONFIG_OUTPUTLOG, "stderr"};
7272
FEXCore::Config::Value<std::string> DumpIR{FEXCore::Config::CONFIG_DUMPIR, "no"};
7373
FEXCore::Config::Value<bool> TSOEnabledConfig{FEXCore::Config::CONFIG_TSO_ENABLED, true};
74-
FEXCore::Config::Value<bool> SMCChecksConfig{FEXCore::Config::CONFIG_SMC_CHECKS, false};
74+
FEXCore::Config::Value<uint8_t> SMCChecksConfig{FEXCore::Config::CONFIG_SMC_CHECKS, FEXCore::Config::CONFIG_SMC_MMAN};
7575
FEXCore::Config::Value<bool> ABILocalFlags{FEXCore::Config::CONFIG_ABI_LOCAL_FLAGS, false};
7676
FEXCore::Config::Value<bool> AbiNoPF{FEXCore::Config::CONFIG_ABI_NO_PF, false};
7777

Source/Tools/FEXConfig/Main.cpp

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -301,11 +301,27 @@ namespace {
301301
ConfigChanged = true;
302302
}
303303

304+
ImGui::Text("SMC Checks: ");
305+
int SMCChecks = FEXCore::Config::CONFIG_SMC_MMAN;
306+
304307
Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_SMC_CHECKS);
305-
bool SMCChecks = Value.has_value() && **Value == "1";
306-
if (ImGui::Checkbox("SMC Checks", &SMCChecks)) {
307-
LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_SMC_CHECKS, SMCChecks ? "1" : "0");
308-
ConfigChanged = true;
308+
if (Value.has_value()) {
309+
if (**Value == "0") {
310+
SMCChecks = FEXCore::Config::CONFIG_SMC_NONE;
311+
} else if (**Value == "1") {
312+
SMCChecks = FEXCore::Config::CONFIG_SMC_MMAN;
313+
} else if (**Value == "2") {
314+
SMCChecks = FEXCore::Config::CONFIG_SMC_FULL;
315+
}
316+
}
317+
318+
bool SMCChanged = false;
319+
SMCChanged |= ImGui::RadioButton("None", &SMCChecks, FEXCore::Config::CONFIG_SMC_NONE); ImGui::SameLine();
320+
SMCChanged |= ImGui::RadioButton("MMan", &SMCChecks, FEXCore::Config::CONFIG_SMC_MMAN); ImGui::SameLine();
321+
SMCChanged |= ImGui::RadioButton("Full", &SMCChecks, FEXCore::Config::CONFIG_SMC_FULL);
322+
323+
if (SMCChanged) {
324+
LoadedConfig->EraseSet(FEXCore::Config::ConfigOption::CONFIG_SMC_CHECKS, std::to_string(SMCChecks));
309325
}
310326

311327
Value = LoadedConfig->Get(FEXCore::Config::ConfigOption::CONFIG_ABI_LOCAL_FLAGS);

unittests/ASM/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ foreach(ASM_SRC ${ASM_SOURCES})
7474
string(REPLACE " " ";" ARGS_LIST ${ARGS})
7575

7676
if (TEST_NAME MATCHES "SelfModifyingCode")
77-
list(APPEND ARGS_LIST "--smc-full-checks")
77+
list(APPEND ARGS_LIST "--smc-checks=full")
7878
endif()
7979

8080
add_test(NAME ${TEST_NAME}

0 commit comments

Comments
 (0)