mirror of
https://github.com/hedge-dev/XenonRecomp.git
synced 2025-04-19 10:51:18 +00:00
Detect MMIO writes via eieio
This commit is contained in:
parent
4357a55eff
commit
e5317bda48
@ -158,6 +158,7 @@ bool Recompiler::Recompile(
|
||||
const Function& fn,
|
||||
uint32_t base,
|
||||
const ppc_insn& insn,
|
||||
const uint32_t* data,
|
||||
std::unordered_map<uint32_t, RecompilerSwitchTable>::iterator& switchTable,
|
||||
RecompilerLocalVariables& localVariables,
|
||||
CSRState& csrState)
|
||||
@ -262,6 +263,12 @@ bool Recompiler::Recompile(
|
||||
return "ea";
|
||||
};
|
||||
|
||||
// TODO (Sajid): Check for out of bounds access
|
||||
auto mmioStore = [&]() -> bool
|
||||
{
|
||||
return *(data + 1) == c_eieio;
|
||||
};
|
||||
|
||||
auto printFunctionCall = [&](uint32_t address)
|
||||
{
|
||||
if (address == config.longJmpAddress)
|
||||
@ -1362,7 +1369,7 @@ bool Recompiler::Recompile(
|
||||
break;
|
||||
|
||||
case PPC_INST_STB:
|
||||
print("\tPPC_STORE_U8(");
|
||||
print("{}", mmioStore() ? "\tPPC_MM_STORE_U8(" : "\tPPC_STORE_U8(");
|
||||
if (insn.operands[2] != 0)
|
||||
print("{}.u32 + ", r(insn.operands[2]));
|
||||
println("{}, {}.u8);", int32_t(insn.operands[1]), r(insn.operands[0]));
|
||||
@ -1375,14 +1382,14 @@ bool Recompiler::Recompile(
|
||||
break;
|
||||
|
||||
case PPC_INST_STBX:
|
||||
print("\tPPC_STORE_U8(");
|
||||
print("{}", mmioStore() ? "\tPPC_MM_STORE_U8(" : "\tPPC_STORE_U8(");
|
||||
if (insn.operands[1] != 0)
|
||||
print("{}.u32 + ", r(insn.operands[1]));
|
||||
println("{}.u32, {}.u8);", r(insn.operands[2]), r(insn.operands[0]));
|
||||
break;
|
||||
|
||||
case PPC_INST_STD:
|
||||
print("\tPPC_STORE_U64(");
|
||||
print("{}", mmioStore() ? "\tPPC_MM_STORE_U64(" : "\tPPC_STORE_U64(");
|
||||
if (insn.operands[2] != 0)
|
||||
print("{}.u32 + ", r(insn.operands[2]));
|
||||
println("{}, {}.u64);", int32_t(insn.operands[1]), r(insn.operands[0]));
|
||||
@ -1405,7 +1412,7 @@ bool Recompiler::Recompile(
|
||||
break;
|
||||
|
||||
case PPC_INST_STDX:
|
||||
print("\tPPC_STORE_U64(");
|
||||
print("{}", mmioStore() ? "\tPPC_MM_STORE_U64(" : "\tPPC_STORE_U64(");
|
||||
if (insn.operands[1] != 0)
|
||||
print("{}.u32 + ", r(insn.operands[1]));
|
||||
println("{}.u32, {}.u64);", r(insn.operands[2]), r(insn.operands[0]));
|
||||
@ -1413,7 +1420,7 @@ bool Recompiler::Recompile(
|
||||
|
||||
case PPC_INST_STFD:
|
||||
printSetFlushMode(false);
|
||||
print("\tPPC_STORE_U64(");
|
||||
print("{}", mmioStore() ? "\tPPC_MM_STORE_U64(" : "\tPPC_STORE_U64(");
|
||||
if (insn.operands[2] != 0)
|
||||
print("{}.u32 + ", r(insn.operands[2]));
|
||||
println("{}, {}.u64);", int32_t(insn.operands[1]), f(insn.operands[0]));
|
||||
@ -1421,7 +1428,7 @@ bool Recompiler::Recompile(
|
||||
|
||||
case PPC_INST_STFDX:
|
||||
printSetFlushMode(false);
|
||||
print("\tPPC_STORE_U64(");
|
||||
print("{}", mmioStore() ? "\tPPC_MM_STORE_U64(" : "\tPPC_STORE_U64(");
|
||||
if (insn.operands[1] != 0)
|
||||
print("{}.u32 + ", r(insn.operands[1]));
|
||||
println("{}.u32, {}.u64);", r(insn.operands[2]), f(insn.operands[0]));
|
||||
@ -1429,7 +1436,7 @@ bool Recompiler::Recompile(
|
||||
|
||||
case PPC_INST_STFIWX:
|
||||
printSetFlushMode(false);
|
||||
print("\tPPC_STORE_U32(");
|
||||
print("{}", mmioStore() ? "\tPPC_MM_STORE_U32(" : "\tPPC_STORE_U32(");
|
||||
if (insn.operands[1] != 0)
|
||||
print("{}.u32 + ", r(insn.operands[1]));
|
||||
println("{}.u32, {}.u32);", r(insn.operands[2]), f(insn.operands[0]));
|
||||
@ -1438,7 +1445,7 @@ bool Recompiler::Recompile(
|
||||
case PPC_INST_STFS:
|
||||
printSetFlushMode(false);
|
||||
println("\t{}.f32 = float({}.f64);", temp(), f(insn.operands[0]));
|
||||
print("\tPPC_STORE_U32(");
|
||||
print("{}", mmioStore() ? "\tPPC_MM_STORE_U32(" : "\tPPC_STORE_U32(");
|
||||
if (insn.operands[2] != 0)
|
||||
print("{}.u32 + ", r(insn.operands[2]));
|
||||
println("{}, {}.u32);", int32_t(insn.operands[1]), temp());
|
||||
@ -1447,28 +1454,28 @@ bool Recompiler::Recompile(
|
||||
case PPC_INST_STFSX:
|
||||
printSetFlushMode(false);
|
||||
println("\t{}.f32 = float({}.f64);", temp(), f(insn.operands[0]));
|
||||
print("\tPPC_STORE_U32(");
|
||||
print("{}", mmioStore() ? "\tPPC_MM_STORE_U32(" : "\tPPC_STORE_U32(");
|
||||
if (insn.operands[1] != 0)
|
||||
print("{}.u32 + ", r(insn.operands[1]));
|
||||
println("{}.u32, {}.u32);", r(insn.operands[2]), temp());
|
||||
break;
|
||||
|
||||
case PPC_INST_STH:
|
||||
print("\tPPC_STORE_U16(");
|
||||
print("{}", mmioStore() ? "\tPPC_MM_STORE_U16(" : "\tPPC_STORE_U16(");
|
||||
if (insn.operands[2] != 0)
|
||||
print("{}.u32 + ", r(insn.operands[2]));
|
||||
println("{}, {}.u16);", int32_t(insn.operands[1]), r(insn.operands[0]));
|
||||
break;
|
||||
|
||||
case PPC_INST_STHBRX:
|
||||
print("\tPPC_STORE_U16(");
|
||||
print("{}", mmioStore() ? "\tPPC_MM_STORE_U16(" : "\tPPC_STORE_U16(");
|
||||
if (insn.operands[1] != 0)
|
||||
print("{}.u32 + ", r(insn.operands[1]));
|
||||
println("{}.u32, __builtin_bswap16({}.u16));", r(insn.operands[2]), r(insn.operands[0]));
|
||||
break;
|
||||
|
||||
case PPC_INST_STHX:
|
||||
print("\tPPC_STORE_U16(");
|
||||
print("{}", mmioStore() ? "\tPPC_MM_STORE_U16(" : "\tPPC_STORE_U16(");
|
||||
if (insn.operands[1] != 0)
|
||||
print("{}.u32 + ", r(insn.operands[1]));
|
||||
println("{}.u32, {}.u16);", r(insn.operands[2]), r(insn.operands[0]));
|
||||
@ -1530,14 +1537,14 @@ bool Recompiler::Recompile(
|
||||
break;
|
||||
|
||||
case PPC_INST_STW:
|
||||
print("\tPPC_STORE_U32(");
|
||||
print("{}", mmioStore() ? "\tPPC_MM_STORE_U32(" : "\tPPC_STORE_U32(");
|
||||
if (insn.operands[2] != 0)
|
||||
print("{}.u32 + ", r(insn.operands[2]));
|
||||
println("{}, {}.u32);", int32_t(insn.operands[1]), r(insn.operands[0]));
|
||||
break;
|
||||
|
||||
case PPC_INST_STWBRX:
|
||||
print("\tPPC_STORE_U32(");
|
||||
print("{}", mmioStore() ? "\tPPC_MM_STORE_U32(" : "\tPPC_STORE_U32(");
|
||||
if (insn.operands[1] != 0)
|
||||
print("{}.u32 + ", r(insn.operands[1]));
|
||||
println("{}.u32, __builtin_bswap32({}.u32));", r(insn.operands[2]), r(insn.operands[0]));
|
||||
@ -1566,7 +1573,7 @@ bool Recompiler::Recompile(
|
||||
break;
|
||||
|
||||
case PPC_INST_STWX:
|
||||
print("\tPPC_STORE_U32(");
|
||||
print("{}", mmioStore() ? "\tPPC_MM_STORE_U32(" : "\tPPC_STORE_U32(");
|
||||
if (insn.operands[1] != 0)
|
||||
print("{}.u32 + ", r(insn.operands[1]));
|
||||
println("{}.u32, {}.u32);", r(insn.operands[2]), r(insn.operands[0]));
|
||||
@ -2287,7 +2294,7 @@ bool Recompiler::Recompile(const Function& fn)
|
||||
if (insn.opcode->id == PPC_INST_BCTR && (*(data - 1) == 0x07008038 || *(data - 1) == 0x00000060) && switchTable == config.switchTables.end())
|
||||
std::println("Found a switch jump table at {:X} with no switch table entry present", base);
|
||||
|
||||
if (!Recompile(fn, base, insn, switchTable, localVariables, csrState))
|
||||
if (!Recompile(fn, base, insn, data, switchTable, localVariables, csrState))
|
||||
{
|
||||
std::println("Unrecognized instruction at 0x{:X}: {}", base, insn.opcode->name);
|
||||
allRecompiled = false;
|
||||
|
@ -27,6 +27,8 @@ enum class CSRState
|
||||
|
||||
struct Recompiler
|
||||
{
|
||||
// Enforce In-order Execution of I/O constant for quick comparison
|
||||
static constexpr uint32_t c_eieio = 0xAC06007C;
|
||||
Image image;
|
||||
std::vector<Function> functions;
|
||||
std::string out;
|
||||
@ -54,7 +56,8 @@ struct Recompiler
|
||||
bool Recompile(
|
||||
const Function& fn,
|
||||
uint32_t base,
|
||||
const ppc_insn& insn,
|
||||
const ppc_insn& insn,
|
||||
const uint32_t* data,
|
||||
std::unordered_map<uint32_t, RecompilerSwitchTable>::iterator& switchTable,
|
||||
RecompilerLocalVariables& localVariables,
|
||||
CSRState& csrState);
|
||||
|
@ -29,11 +29,27 @@
|
||||
#define PPC_LOAD_U32(x) __builtin_bswap32(*(volatile uint32_t*)(base + (x)))
|
||||
#define PPC_LOAD_U64(x) __builtin_bswap64(*(volatile uint64_t*)(base + (x)))
|
||||
|
||||
// TODO: Implement.
|
||||
// These are currently unused. However, MMIO loads could possibly be handled statically with some profiling and a fallback.
|
||||
// The fallback would be a runtime exception handler which will intercept reads from MMIO regions
|
||||
// and log the PC for compiling to static code later.
|
||||
#define PPC_MM_LOAD_U8(x) PPC_LOAD_U8 (x)
|
||||
#define PPC_MM_LOAD_U16(x) PPC_LOAD_U16(x)
|
||||
#define PPC_MM_LOAD_U32(x) PPC_LOAD_U32(x)
|
||||
#define PPC_MM_LOAD_U64(x) PPC_LOAD_U64(x)
|
||||
|
||||
#define PPC_STORE_U8(x, y) *(volatile uint8_t*)(base + (x)) = (y)
|
||||
#define PPC_STORE_U16(x, y) *(volatile uint16_t*)(base + (x)) = __builtin_bswap16(y)
|
||||
#define PPC_STORE_U32(x, y) *(volatile uint32_t*)(base + (x)) = __builtin_bswap32(y)
|
||||
#define PPC_STORE_U64(x, y) *(volatile uint64_t*)(base + (x)) = __builtin_bswap64(y)
|
||||
|
||||
// MMIO Store handling is completely reliant on being preeceded by eieio.
|
||||
// TODO: Verify if that's always the case.
|
||||
#define PPC_MM_STORE_U8(x, y) PPC_STORE_U8 (x, y)
|
||||
#define PPC_MM_STORE_U16(x, y) PPC_STORE_U16(x, y)
|
||||
#define PPC_MM_STORE_U32(x, y) PPC_STORE_U32(x, y)
|
||||
#define PPC_MM_STORE_U64(x, y) PPC_STORE_U64(x, y)
|
||||
|
||||
#define PPC_CALL_FUNC(x) x(ctx, base)
|
||||
#define PPC_CALL_INDIRECT_FUNC(x) (*(PPCFunc**)(ctx.fn + uint64_t(x) * 2))(ctx, base)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user