mirror of
https://github.com/FEX-Emu/FEX.git
synced 2025-01-10 15:50:18 +00:00
SMC: Add --smc-full-checks, implement frontend, irint, irjit, unit test
This commit is contained in:
parent
c28a684305
commit
df3bdf361f
@ -36,6 +36,9 @@ namespace FEXCore::Config {
|
|||||||
case FEXCore::Config::CONFIG_TSO_ENABLED:
|
case FEXCore::Config::CONFIG_TSO_ENABLED:
|
||||||
CTX->Config.TSOEnabled = Config != 0;
|
CTX->Config.TSOEnabled = Config != 0;
|
||||||
break;
|
break;
|
||||||
|
case FEXCore::Config::CONFIG_SMC_CHECKS:
|
||||||
|
CTX->Config.SMCChecks = Config != 0;
|
||||||
|
break;
|
||||||
default: LogMan::Msg::A("Unknown configuration option");
|
default: LogMan::Msg::A("Unknown configuration option");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -83,6 +86,9 @@ namespace FEXCore::Config {
|
|||||||
case FEXCore::Config::CONFIG_TSO_ENABLED:
|
case FEXCore::Config::CONFIG_TSO_ENABLED:
|
||||||
return CTX->Config.TSOEnabled;
|
return CTX->Config.TSOEnabled;
|
||||||
break;
|
break;
|
||||||
|
case FEXCore::Config::CONFIG_SMC_CHECKS:
|
||||||
|
return CTX->Config.SMCChecks;
|
||||||
|
break;
|
||||||
default: LogMan::Msg::A("Unknown configuration option");
|
default: LogMan::Msg::A("Unknown configuration option");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,6 +60,7 @@ namespace FEXCore::Context {
|
|||||||
bool Is64BitMode {true};
|
bool Is64BitMode {true};
|
||||||
uint64_t EmulatedCPUCores{1};
|
uint64_t EmulatedCPUCores{1};
|
||||||
bool TSOEnabled {true};
|
bool TSOEnabled {true};
|
||||||
|
bool SMCChecks {false};
|
||||||
} Config;
|
} Config;
|
||||||
|
|
||||||
FEXCore::Memory::MemMapper MemoryMapper;
|
FEXCore::Memory::MemMapper MemoryMapper;
|
||||||
@ -113,6 +114,8 @@ namespace FEXCore::Context {
|
|||||||
void StopGdbServer();
|
void StopGdbServer();
|
||||||
void HandleCallback(uint64_t RIP);
|
void HandleCallback(uint64_t RIP);
|
||||||
|
|
||||||
|
static void RemoveCodeEntry(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestRIP);
|
||||||
|
|
||||||
// Debugger interface
|
// Debugger interface
|
||||||
void CompileRIP(FEXCore::Core::InternalThreadState *Thread, uint64_t RIP);
|
void CompileRIP(FEXCore::Core::InternalThreadState *Thread, uint64_t RIP);
|
||||||
uint64_t GetThreadCount() const;
|
uint64_t GetThreadCount() const;
|
||||||
|
37
External/FEXCore/Source/Interface/Core/Core.cpp
vendored
37
External/FEXCore/Source/Interface/Core/Core.cpp
vendored
@ -647,6 +647,37 @@ namespace FEXCore::Context {
|
|||||||
TableInfo = Block.DecodedInstructions[i].TableInfo;
|
TableInfo = Block.DecodedInstructions[i].TableInfo;
|
||||||
DecodedInfo = &Block.DecodedInstructions[i];
|
DecodedInfo = &Block.DecodedInstructions[i];
|
||||||
|
|
||||||
|
if (Config.SMCChecks) {
|
||||||
|
__uint128_t existing;
|
||||||
|
|
||||||
|
uintptr_t ExistingCodePtr{};
|
||||||
|
|
||||||
|
if (Thread->CTX->Config.UnifiedMemory) {
|
||||||
|
ExistingCodePtr = reinterpret_cast<uintptr_t>(Block.Entry + BlockInstructionsLength);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ExistingCodePtr = MemoryMapper.GetPointer<uintptr_t>(Block.Entry + BlockInstructionsLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&existing, (void*)(ExistingCodePtr), DecodedInfo->InstSize);
|
||||||
|
auto CodeChanged = Thread->OpDispatcher->_ValidateCode(existing, ExistingCodePtr, DecodedInfo->InstSize);
|
||||||
|
|
||||||
|
auto InvalidateCodeCond = Thread->OpDispatcher->_CondJump(CodeChanged);
|
||||||
|
|
||||||
|
auto CodeWasChangedBlock = Thread->OpDispatcher->CreateNewCodeBlock();
|
||||||
|
Thread->OpDispatcher->SetTrueJumpTarget(InvalidateCodeCond, CodeWasChangedBlock);
|
||||||
|
|
||||||
|
Thread->OpDispatcher->SetCurrentCodeBlock(CodeWasChangedBlock);
|
||||||
|
Thread->OpDispatcher->_RemoveCodeEntry(GuestRIP);
|
||||||
|
Thread->OpDispatcher->_StoreContext(IR::GPRClass, 8, offsetof(FEXCore::Core::CPUState, rip), Thread->OpDispatcher->_Constant(Block.Entry + BlockInstructionsLength));
|
||||||
|
Thread->OpDispatcher->_ExitFunction();
|
||||||
|
|
||||||
|
auto NextOpBlock = Thread->OpDispatcher->CreateNewCodeBlock();
|
||||||
|
|
||||||
|
Thread->OpDispatcher->SetFalseJumpTarget(InvalidateCodeCond, NextOpBlock);
|
||||||
|
Thread->OpDispatcher->SetCurrentCodeBlock(NextOpBlock);
|
||||||
|
}
|
||||||
|
|
||||||
if (TableInfo->OpcodeDispatcher) {
|
if (TableInfo->OpcodeDispatcher) {
|
||||||
auto Fn = TableInfo->OpcodeDispatcher;
|
auto Fn = TableInfo->OpcodeDispatcher;
|
||||||
std::invoke(Fn, Thread->OpDispatcher, DecodedInfo);
|
std::invoke(Fn, Thread->OpDispatcher, DecodedInfo);
|
||||||
@ -799,6 +830,12 @@ namespace FEXCore::Context {
|
|||||||
SignalDelegation.UninstallTLSState(Thread);
|
SignalDelegation.UninstallTLSState(Thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Context::RemoveCodeEntry(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestRIP) {
|
||||||
|
Thread->IRLists.erase(GuestRIP);
|
||||||
|
Thread->DebugData.erase(GuestRIP);
|
||||||
|
Thread->BlockCache->Erase(GuestRIP);
|
||||||
|
}
|
||||||
|
|
||||||
// Debug interface
|
// Debug interface
|
||||||
void Context::CompileRIP(FEXCore::Core::InternalThreadState *Thread, uint64_t RIP) {
|
void Context::CompileRIP(FEXCore::Core::InternalThreadState *Thread, uint64_t RIP) {
|
||||||
uint64_t RIPBackup = Thread->State.State.rip;
|
uint64_t RIPBackup = Thread->State.State.rip;
|
||||||
|
@ -138,6 +138,23 @@ void InterpreterCore::ExecuteCode(FEXCore::Core::InternalThreadState *Thread) {
|
|||||||
uint32_t Node = WrapperOp.ID();
|
uint32_t Node = WrapperOp.ID();
|
||||||
|
|
||||||
switch (IROp->Op) {
|
switch (IROp->Op) {
|
||||||
|
case IR::OP_VALIDATECODE: {
|
||||||
|
auto Op = IROp->C<IR::IROp_ValidateCode>();
|
||||||
|
|
||||||
|
if (memcmp((void*)Op->CodePtr, &Op->CodeOriginal, Op->CodeLength) != 0) {
|
||||||
|
GD = 1;
|
||||||
|
} else {
|
||||||
|
GD = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case IR::OP_REMOVECODEENTRY: {
|
||||||
|
auto Op = IROp->C<IR::IROp_RemoveCodeEntry>();
|
||||||
|
CTX->RemoveCodeEntry(Thread, Op->RIP);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case IR::OP_DUMMY:
|
case IR::OP_DUMMY:
|
||||||
case IR::OP_BEGINBLOCK:
|
case IR::OP_BEGINBLOCK:
|
||||||
break;
|
break;
|
||||||
|
@ -115,6 +115,11 @@ DispatchGenerator::DispatchGenerator(FEXCore::Context::Context *ctx, FEXCore::Co
|
|||||||
|
|
||||||
shl(rax, (int)log2(sizeof(FEXCore::BlockCache::BlockCacheEntry)));
|
shl(rax, (int)log2(sizeof(FEXCore::BlockCache::BlockCacheEntry)));
|
||||||
|
|
||||||
|
// check for aliasing
|
||||||
|
mov(rcx, qword [rdi + rax + 8]);
|
||||||
|
cmp(rcx, rdx);
|
||||||
|
jne(NoBlock);
|
||||||
|
|
||||||
// Load the block pointer
|
// Load the block pointer
|
||||||
mov(rax, qword [rdi + rax]);
|
mov(rax, qword [rdi + rax]);
|
||||||
|
|
||||||
|
@ -184,6 +184,82 @@ DEF_OP(Thunk) {
|
|||||||
add(sp, sp, SPOffset);
|
add(sp, sp, SPOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DEF_OP(ValidateCode) {
|
||||||
|
auto Op = IROp->C<IR::IROp_ValidateCode>();
|
||||||
|
uint8_t *NewCode = (uint8_t *)Op->CodePtr;
|
||||||
|
uint8_t *OldCode = (uint8_t *)&Op->CodeOriginal;
|
||||||
|
int len = Op->CodeLength;
|
||||||
|
int idx = 0;
|
||||||
|
|
||||||
|
LoadConstant(GetReg<RA_64>(Node), 0);
|
||||||
|
LoadConstant(x0, Op->CodePtr);
|
||||||
|
LoadConstant(x1, 1);
|
||||||
|
|
||||||
|
while (len >= 4)
|
||||||
|
{
|
||||||
|
ldr(w2, MemOperand(x0, idx));
|
||||||
|
LoadConstant(w3, *(uint32_t *)(OldCode + idx));
|
||||||
|
cmp(w2, w3);
|
||||||
|
csel(GetReg<RA_64>(Node), GetReg<RA_64>(Node), x1, Condition::eq);
|
||||||
|
len -= 4;
|
||||||
|
idx += 4;
|
||||||
|
}
|
||||||
|
while (len >= 2)
|
||||||
|
{
|
||||||
|
ldrh(w2, MemOperand(x0, idx));
|
||||||
|
LoadConstant(w3, *(uint16_t *)(OldCode + idx));
|
||||||
|
cmp(w2, w3);
|
||||||
|
csel(GetReg<RA_64>(Node), GetReg<RA_64>(Node), x1, Condition::eq);
|
||||||
|
len -= 2;
|
||||||
|
idx += 2;
|
||||||
|
}
|
||||||
|
while (len >= 1)
|
||||||
|
{
|
||||||
|
ldrb(w2, MemOperand(x0, idx));
|
||||||
|
LoadConstant(w3, *(uint8_t *)(OldCode + idx));
|
||||||
|
cmp(w2, w3);
|
||||||
|
csel(GetReg<RA_64>(Node), GetReg<RA_64>(Node), x1, Condition::eq);
|
||||||
|
len -= 1;
|
||||||
|
idx += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DEF_OP(RemoveCodeEntry) {
|
||||||
|
auto Op = IROp->C<IR::IROp_RemoveCodeEntry>();
|
||||||
|
// Arguments are passed as follows:
|
||||||
|
// X0: Thread
|
||||||
|
// X1: RIP
|
||||||
|
|
||||||
|
uint64_t SPOffset = AlignUp((RA64.size() + 1) * 8, 16);
|
||||||
|
|
||||||
|
sub(sp, sp, SPOffset);
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for (auto RA : RA64) {
|
||||||
|
str(RA, MemOperand(sp, i * 8));
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
str(lr, MemOperand(sp, RA64.size() * 8 + 0 * 8));
|
||||||
|
|
||||||
|
mov(x0, STATE);
|
||||||
|
LoadConstant(x1, Op->RIP);
|
||||||
|
|
||||||
|
LoadConstant(x2, reinterpret_cast<uintptr_t>(&Context::Context::RemoveCodeEntry));
|
||||||
|
blr(x2);
|
||||||
|
|
||||||
|
// Fix the stack and any values that were stepped on
|
||||||
|
i = 0;
|
||||||
|
for (auto RA : RA64) {
|
||||||
|
ldr(RA, MemOperand(sp, i * 8));
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
ldr(lr, MemOperand(sp, RA64.size() * 8 + 0 * 8));
|
||||||
|
|
||||||
|
add(sp, sp, SPOffset);
|
||||||
|
}
|
||||||
|
|
||||||
DEF_OP(CPUID) {
|
DEF_OP(CPUID) {
|
||||||
auto Op = IROp->C<IR::IROp_CPUID>();
|
auto Op = IROp->C<IR::IROp_CPUID>();
|
||||||
uint64_t SPOffset = AlignUp((RA64.size() + 2 + 2) * 8, 16);
|
uint64_t SPOffset = AlignUp((RA64.size() + 2 + 2) * 8, 16);
|
||||||
@ -243,6 +319,8 @@ void JITCore::RegisterBranchHandlers() {
|
|||||||
REGISTER_OP(CONDJUMP, CondJump);
|
REGISTER_OP(CONDJUMP, CondJump);
|
||||||
REGISTER_OP(SYSCALL, Syscall);
|
REGISTER_OP(SYSCALL, Syscall);
|
||||||
REGISTER_OP(THUNK, Thunk);
|
REGISTER_OP(THUNK, Thunk);
|
||||||
|
REGISTER_OP(VALIDATECODE, ValidateCode);
|
||||||
|
REGISTER_OP(REMOVECODEENTRY, RemoveCodeEntry);
|
||||||
REGISTER_OP(CPUID, CPUID);
|
REGISTER_OP(CPUID, CPUID);
|
||||||
#undef REGISTER_OP
|
#undef REGISTER_OP
|
||||||
}
|
}
|
||||||
|
@ -309,6 +309,8 @@ private:
|
|||||||
DEF_OP(CondJump);
|
DEF_OP(CondJump);
|
||||||
DEF_OP(Syscall);
|
DEF_OP(Syscall);
|
||||||
DEF_OP(Thunk);
|
DEF_OP(Thunk);
|
||||||
|
DEF_OP(ValidateCode);
|
||||||
|
DEF_OP(RemoveCodeEntry);
|
||||||
DEF_OP(CPUID);
|
DEF_OP(CPUID);
|
||||||
|
|
||||||
///< Conversion ops
|
///< Conversion ops
|
||||||
|
@ -4845,6 +4845,65 @@ void *JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView<true> const
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case IR::OP_VALIDATECODE:
|
||||||
|
{
|
||||||
|
auto Op = IROp->C<IR::IROp_ValidateCode>();
|
||||||
|
uint8_t* NewCode = (uint8_t*)Op->CodePtr;
|
||||||
|
uint8_t* OldCode = (uint8_t*)&Op->CodeOriginal;
|
||||||
|
int len = Op->CodeLength;
|
||||||
|
int idx = 0;
|
||||||
|
|
||||||
|
xor_(GetDst<RA_64>(Node), GetDst<RA_64>(Node));
|
||||||
|
mov(rax, Op->CodePtr);
|
||||||
|
mov(rbx, 1);
|
||||||
|
while (len >= 4) {
|
||||||
|
cmp(dword[rax + idx], *(uint32_t*)(OldCode + idx));
|
||||||
|
cmovne(GetDst<RA_64>(Node), rbx);
|
||||||
|
len-=4;
|
||||||
|
idx+=4;
|
||||||
|
}
|
||||||
|
while (len >= 2) {
|
||||||
|
mov(rcx, *(uint16_t*)(OldCode + idx));
|
||||||
|
cmp(word[rax + idx], cx);
|
||||||
|
cmovne(GetDst<RA_64>(Node), rbx);
|
||||||
|
len-=2;
|
||||||
|
idx+=2;
|
||||||
|
}
|
||||||
|
while (len >= 1) {
|
||||||
|
cmp(byte[rax + idx], *(uint8_t*)(OldCode + idx));
|
||||||
|
cmovne(GetDst<RA_64>(Node), rbx);
|
||||||
|
len-=1;
|
||||||
|
idx+=1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case IR::OP_REMOVECODEENTRY: {
|
||||||
|
auto Op = IROp->C<IR::IROp_RemoveCodeEntry>();
|
||||||
|
|
||||||
|
auto NumPush = RA64.size();
|
||||||
|
|
||||||
|
for (auto &Reg : RA64)
|
||||||
|
push(Reg);
|
||||||
|
|
||||||
|
if (NumPush & 1)
|
||||||
|
sub(rsp, 8); // Align
|
||||||
|
|
||||||
|
mov(rdi, STATE);
|
||||||
|
mov(rax, Op->RIP); // imm64 move
|
||||||
|
mov(rsi, rax);
|
||||||
|
|
||||||
|
|
||||||
|
mov(rax, reinterpret_cast<uintptr_t>(&Context::Context::RemoveCodeEntry));
|
||||||
|
call(rax);
|
||||||
|
|
||||||
|
if (NumPush & 1)
|
||||||
|
add(rsp, 8); // Align
|
||||||
|
|
||||||
|
for (uint32_t i = RA64.size(); i > 0; --i)
|
||||||
|
pop(RA64[i - 1]);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
case IR::OP_DUMMY:
|
case IR::OP_DUMMY:
|
||||||
case IR::OP_IRHEADER:
|
case IR::OP_IRHEADER:
|
||||||
case IR::OP_PHIVALUE:
|
case IR::OP_PHIVALUE:
|
||||||
@ -4971,6 +5030,11 @@ void JITCore::CreateCustomDispatch(FEXCore::Core::InternalThreadState *Thread) {
|
|||||||
|
|
||||||
shl(rax, (int)log2(sizeof(FEXCore::BlockCache::BlockCacheEntry)));
|
shl(rax, (int)log2(sizeof(FEXCore::BlockCache::BlockCacheEntry)));
|
||||||
|
|
||||||
|
// check for aliasing
|
||||||
|
mov(rcx, qword [rdi + rax + 8]);
|
||||||
|
cmp(rcx, rdx);
|
||||||
|
jne(NoBlock);
|
||||||
|
|
||||||
// Load the block pointer
|
// Load the block pointer
|
||||||
mov(rax, qword [rdi + rax]);
|
mov(rax, qword [rdi + rax]);
|
||||||
|
|
||||||
|
21
External/FEXCore/Source/Interface/IR/IR.json
vendored
21
External/FEXCore/Source/Interface/IR/IR.json
vendored
@ -86,6 +86,27 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"ValidateCode": {
|
||||||
|
"HasSideEffects": true,
|
||||||
|
"OpClass": "Misc",
|
||||||
|
"HasDest": true,
|
||||||
|
"DestClass": "GPR",
|
||||||
|
"DestSize": "8",
|
||||||
|
"Args": [
|
||||||
|
"__uint128_t", "CodeOriginal",
|
||||||
|
"uint64_t", "CodePtr",
|
||||||
|
"uint8_t", "CodeLength"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
"RemoveCodeEntry": {
|
||||||
|
"HasSideEffects": true,
|
||||||
|
"OpClass": "Misc",
|
||||||
|
"Args": [
|
||||||
|
"uint64_t", "RIP"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
"GuestCallDirect": {
|
"GuestCallDirect": {
|
||||||
"OpClass": "Branch",
|
"OpClass": "Branch",
|
||||||
"Args": [
|
"Args": [
|
||||||
|
@ -17,6 +17,7 @@ namespace FEXCore::Config {
|
|||||||
CONFIG_IS64BIT_MODE,
|
CONFIG_IS64BIT_MODE,
|
||||||
CONFIG_EMULATED_CPU_CORES,
|
CONFIG_EMULATED_CPU_CORES,
|
||||||
CONFIG_TSO_ENABLED,
|
CONFIG_TSO_ENABLED,
|
||||||
|
CONFIG_SMC_CHECKS
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ConfigCore {
|
enum ConfigCore {
|
||||||
|
@ -68,6 +68,12 @@ namespace FEX::ArgLoader {
|
|||||||
.help("Disables TSO IR ops. Highly likely to break any threaded application")
|
.help("Disables TSO IR ops. Highly likely to break any threaded application")
|
||||||
.set_default(true);
|
.set_default(true);
|
||||||
|
|
||||||
|
CPUGroup.add_option("--smc-full-checks")
|
||||||
|
.dest("SMCChecks")
|
||||||
|
.action("store_true")
|
||||||
|
.help("Checks code for modification before execution. Slow.")
|
||||||
|
.set_default(false);
|
||||||
|
|
||||||
Parser.add_option_group(CPUGroup);
|
Parser.add_option_group(CPUGroup);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
@ -190,6 +196,11 @@ namespace FEX::ArgLoader {
|
|||||||
bool TSOEnabled = Options.get("TSOEnabled");
|
bool TSOEnabled = Options.get("TSOEnabled");
|
||||||
Config::Add("TSOEnabled", std::to_string(TSOEnabled));
|
Config::Add("TSOEnabled", std::to_string(TSOEnabled));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Options.is_set_by_user("SMCChecks")) {
|
||||||
|
bool SMCChecks = Options.get("SMCChecks");
|
||||||
|
Config::Add("SMCChecks", std::to_string(SMCChecks));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -81,6 +81,10 @@ namespace FEX::EnvLoader {
|
|||||||
if ((Value = GetVar("FEX_TSO_ENABLED")).size()) {
|
if ((Value = GetVar("FEX_TSO_ENABLED")).size()) {
|
||||||
if (isdigit(Value[0])) Config::Add("TSOEnabled", Value);
|
if (isdigit(Value[0])) Config::Add("TSOEnabled", Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((Value = GetVar("FEX_SMC_CHECKS")).size()) {
|
||||||
|
if (isdigit(Value[0])) Config::Add("SMCChecks", Value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -110,6 +110,7 @@ int main(int argc, char **argv, char **const envp) {
|
|||||||
FEX::Config::Value<std::string> Environment{"Env", ""};
|
FEX::Config::Value<std::string> Environment{"Env", ""};
|
||||||
FEX::Config::Value<std::string> OutputLog{"OutputLog", "stderr"};
|
FEX::Config::Value<std::string> OutputLog{"OutputLog", "stderr"};
|
||||||
FEX::Config::Value<bool> TSOEnabledConfig{"TSOEnabled", true};
|
FEX::Config::Value<bool> TSOEnabledConfig{"TSOEnabled", true};
|
||||||
|
FEX::Config::Value<bool> SMCChecksConfig{"SMCChecks", false};
|
||||||
|
|
||||||
::SilentLog = SilentLog();
|
::SilentLog = SilentLog();
|
||||||
|
|
||||||
@ -154,6 +155,8 @@ int main(int argc, char **argv, char **const envp) {
|
|||||||
FEXCore::Config::SetConfig(CTX, FEXCore::Config::CONFIG_IS64BIT_MODE, Loader.Is64BitMode());
|
FEXCore::Config::SetConfig(CTX, FEXCore::Config::CONFIG_IS64BIT_MODE, Loader.Is64BitMode());
|
||||||
FEXCore::Config::SetConfig(CTX, FEXCore::Config::CONFIG_EMULATED_CPU_CORES, ThreadsConfig());
|
FEXCore::Config::SetConfig(CTX, FEXCore::Config::CONFIG_EMULATED_CPU_CORES, ThreadsConfig());
|
||||||
FEXCore::Config::SetConfig(CTX, FEXCore::Config::CONFIG_TSO_ENABLED, TSOEnabledConfig());
|
FEXCore::Config::SetConfig(CTX, FEXCore::Config::CONFIG_TSO_ENABLED, TSOEnabledConfig());
|
||||||
|
FEXCore::Config::SetConfig(CTX, FEXCore::Config::CONFIG_SMC_CHECKS, SMCChecksConfig());
|
||||||
|
|
||||||
FEXCore::Context::SetCustomCPUBackendFactory(CTX, VMFactory::CPUCreationFactory);
|
FEXCore::Context::SetCustomCPUBackendFactory(CTX, VMFactory::CPUCreationFactory);
|
||||||
// FEXCore::Context::SetFallbackCPUBackendFactory(CTX, VMFactory::CPUCreationFactoryFallback);
|
// FEXCore::Context::SetFallbackCPUBackendFactory(CTX, VMFactory::CPUCreationFactoryFallback);
|
||||||
|
|
||||||
|
@ -60,6 +60,7 @@ int main(int argc, char **argv, char **const envp) {
|
|||||||
FEX::Config::Value<uint64_t> BlockSizeConfig{"MaxInst", 1};
|
FEX::Config::Value<uint64_t> BlockSizeConfig{"MaxInst", 1};
|
||||||
FEX::Config::Value<bool> SingleStepConfig{"SingleStep", false};
|
FEX::Config::Value<bool> SingleStepConfig{"SingleStep", false};
|
||||||
FEX::Config::Value<bool> MultiblockConfig{"Multiblock", false};
|
FEX::Config::Value<bool> MultiblockConfig{"Multiblock", false};
|
||||||
|
FEX::Config::Value<bool> SMCChecksConfig{"SMCChecks", false};
|
||||||
|
|
||||||
auto Args = FEX::ArgLoader::Get();
|
auto Args = FEX::ArgLoader::Get();
|
||||||
|
|
||||||
@ -78,6 +79,7 @@ int main(int argc, char **argv, char **const envp) {
|
|||||||
FEXCore::Config::SetConfig(CTX, FEXCore::Config::CONFIG_SINGLESTEP, SingleStepConfig());
|
FEXCore::Config::SetConfig(CTX, FEXCore::Config::CONFIG_SINGLESTEP, SingleStepConfig());
|
||||||
FEXCore::Config::SetConfig(CTX, FEXCore::Config::CONFIG_MAXBLOCKINST, BlockSizeConfig());
|
FEXCore::Config::SetConfig(CTX, FEXCore::Config::CONFIG_MAXBLOCKINST, BlockSizeConfig());
|
||||||
FEXCore::Config::SetConfig(CTX, FEXCore::Config::CONFIG_IS64BIT_MODE, Loader.Is64BitMode());
|
FEXCore::Config::SetConfig(CTX, FEXCore::Config::CONFIG_IS64BIT_MODE, Loader.Is64BitMode());
|
||||||
|
FEXCore::Config::SetConfig(CTX, FEXCore::Config::CONFIG_SMC_CHECKS, SMCChecksConfig());
|
||||||
FEXCore::Context::SetCustomCPUBackendFactory(CTX, VMFactory::CPUCreationFactory);
|
FEXCore::Context::SetCustomCPUBackendFactory(CTX, VMFactory::CPUCreationFactory);
|
||||||
|
|
||||||
FEXCore::Context::AddGuestMemoryRegion(CTX, SHM);
|
FEXCore::Context::AddGuestMemoryRegion(CTX, SHM);
|
||||||
|
@ -61,6 +61,11 @@ foreach(ASM_SRC ${ASM_SOURCES})
|
|||||||
|
|
||||||
set(TEST_NAME "${TEST_DESC}/Test_${REL_TEST_ASM}")
|
set(TEST_NAME "${TEST_DESC}/Test_${REL_TEST_ASM}")
|
||||||
string(REPLACE " " ";" ARGS_LIST ${ARGS})
|
string(REPLACE " " ";" ARGS_LIST ${ARGS})
|
||||||
|
|
||||||
|
if (TEST_NAME MATCHES "SelfModifyingCode")
|
||||||
|
list(APPEND ARGS_LIST "--smc-full-checks")
|
||||||
|
endif()
|
||||||
|
|
||||||
add_test(NAME ${TEST_NAME}
|
add_test(NAME ${TEST_NAME}
|
||||||
COMMAND "python3" "${CMAKE_SOURCE_DIR}/Scripts/testharness_runner.py"
|
COMMAND "python3" "${CMAKE_SOURCE_DIR}/Scripts/testharness_runner.py"
|
||||||
"${CMAKE_SOURCE_DIR}/unittests/ASM/Known_Failures"
|
"${CMAKE_SOURCE_DIR}/unittests/ASM/Known_Failures"
|
||||||
|
26
unittests/ASM/SelfModifyingCode/DifferentBlock.asm
Normal file
26
unittests/ASM/SelfModifyingCode/DifferentBlock.asm
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
%ifdef CONFIG
|
||||||
|
{
|
||||||
|
"Match": "All",
|
||||||
|
"RegData": {
|
||||||
|
"RAX": "0x20"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
%endif
|
||||||
|
|
||||||
|
jmp main
|
||||||
|
|
||||||
|
patched_op:
|
||||||
|
mov rax,-1
|
||||||
|
ret
|
||||||
|
|
||||||
|
main:
|
||||||
|
|
||||||
|
; warm up the cache
|
||||||
|
call patched_op
|
||||||
|
|
||||||
|
mov byte [rel patched_op], 0xC3
|
||||||
|
|
||||||
|
mov rax, 32
|
||||||
|
call patched_op
|
||||||
|
|
||||||
|
hlt
|
28
unittests/ASM/SelfModifyingCode/SameBlock.asm
Normal file
28
unittests/ASM/SelfModifyingCode/SameBlock.asm
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
%ifdef CONFIG
|
||||||
|
{
|
||||||
|
"Match": "All",
|
||||||
|
"RegData": {
|
||||||
|
"RAX": "0x20"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
%endif
|
||||||
|
|
||||||
|
|
||||||
|
mov rax, 32
|
||||||
|
|
||||||
|
; patch mov rax,... to nops
|
||||||
|
mov byte [rel patched_op + 0], 0x90
|
||||||
|
mov byte [rel patched_op + 1], 0x90
|
||||||
|
mov byte [rel patched_op + 2], 0x90
|
||||||
|
mov byte [rel patched_op + 3], 0x90
|
||||||
|
mov byte [rel patched_op + 4], 0x90
|
||||||
|
mov byte [rel patched_op + 5], 0x90
|
||||||
|
mov byte [rel patched_op + 6], 0x90
|
||||||
|
mov byte [rel patched_op + 7], 0x90
|
||||||
|
mov byte [rel patched_op + 8], 0x90
|
||||||
|
mov byte [rel patched_op + 9], 0x90
|
||||||
|
|
||||||
|
patched_op:
|
||||||
|
mov rax,0xFABCFABCFABC0123 ; 10 bytes long
|
||||||
|
|
||||||
|
hlt
|
Loading…
Reference in New Issue
Block a user