mirror of
				https://github.com/hedge-dev/XenonRecomp.git
				synced 2025-11-04 06:47:09 +00:00 
			
		
		
		
	Detect MMIO writes via eieio
This commit is contained in:
		@@ -158,6 +158,7 @@ bool Recompiler::Recompile(
 | 
				
			|||||||
    const Function& fn,
 | 
					    const Function& fn,
 | 
				
			||||||
    uint32_t base,
 | 
					    uint32_t base,
 | 
				
			||||||
    const ppc_insn& insn,
 | 
					    const ppc_insn& insn,
 | 
				
			||||||
 | 
					    const uint32_t* data,
 | 
				
			||||||
    std::unordered_map<uint32_t, RecompilerSwitchTable>::iterator& switchTable,
 | 
					    std::unordered_map<uint32_t, RecompilerSwitchTable>::iterator& switchTable,
 | 
				
			||||||
    RecompilerLocalVariables& localVariables,
 | 
					    RecompilerLocalVariables& localVariables,
 | 
				
			||||||
    CSRState& csrState)
 | 
					    CSRState& csrState)
 | 
				
			||||||
@@ -262,6 +263,12 @@ bool Recompiler::Recompile(
 | 
				
			|||||||
            return "ea";
 | 
					            return "ea";
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // TODO (Sajid): Check for out of bounds access
 | 
				
			||||||
 | 
					    auto mmioStore = [&]() -> bool
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return *(data + 1) == c_eieio;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    auto printFunctionCall = [&](uint32_t address)
 | 
					    auto printFunctionCall = [&](uint32_t address)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (address == config.longJmpAddress)
 | 
					            if (address == config.longJmpAddress)
 | 
				
			||||||
@@ -1362,7 +1369,7 @@ bool Recompiler::Recompile(
 | 
				
			|||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case PPC_INST_STB:
 | 
					    case PPC_INST_STB:
 | 
				
			||||||
        print("\tPPC_STORE_U8(");
 | 
					        print("{}", mmioStore() ? "\tPPC_MM_STORE_U8(" : "\tPPC_STORE_U8(");
 | 
				
			||||||
        if (insn.operands[2] != 0)
 | 
					        if (insn.operands[2] != 0)
 | 
				
			||||||
            print("{}.u32 + ", r(insn.operands[2]));
 | 
					            print("{}.u32 + ", r(insn.operands[2]));
 | 
				
			||||||
        println("{}, {}.u8);", int32_t(insn.operands[1]), r(insn.operands[0]));
 | 
					        println("{}, {}.u8);", int32_t(insn.operands[1]), r(insn.operands[0]));
 | 
				
			||||||
@@ -1375,14 +1382,14 @@ bool Recompiler::Recompile(
 | 
				
			|||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case PPC_INST_STBX:
 | 
					    case PPC_INST_STBX:
 | 
				
			||||||
        print("\tPPC_STORE_U8(");
 | 
					        print("{}", mmioStore() ? "\tPPC_MM_STORE_U8(" : "\tPPC_STORE_U8(");
 | 
				
			||||||
        if (insn.operands[1] != 0)
 | 
					        if (insn.operands[1] != 0)
 | 
				
			||||||
            print("{}.u32 + ", r(insn.operands[1]));
 | 
					            print("{}.u32 + ", r(insn.operands[1]));
 | 
				
			||||||
        println("{}.u32, {}.u8);", r(insn.operands[2]), r(insn.operands[0]));
 | 
					        println("{}.u32, {}.u8);", r(insn.operands[2]), r(insn.operands[0]));
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case PPC_INST_STD:
 | 
					    case PPC_INST_STD:
 | 
				
			||||||
        print("\tPPC_STORE_U64(");
 | 
					        print("{}", mmioStore() ? "\tPPC_MM_STORE_U64(" : "\tPPC_STORE_U64(");
 | 
				
			||||||
        if (insn.operands[2] != 0)
 | 
					        if (insn.operands[2] != 0)
 | 
				
			||||||
            print("{}.u32 + ", r(insn.operands[2]));
 | 
					            print("{}.u32 + ", r(insn.operands[2]));
 | 
				
			||||||
        println("{}, {}.u64);", int32_t(insn.operands[1]), r(insn.operands[0]));
 | 
					        println("{}, {}.u64);", int32_t(insn.operands[1]), r(insn.operands[0]));
 | 
				
			||||||
@@ -1405,7 +1412,7 @@ bool Recompiler::Recompile(
 | 
				
			|||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case PPC_INST_STDX:
 | 
					    case PPC_INST_STDX:
 | 
				
			||||||
        print("\tPPC_STORE_U64(");
 | 
					        print("{}", mmioStore() ? "\tPPC_MM_STORE_U64(" : "\tPPC_STORE_U64(");
 | 
				
			||||||
        if (insn.operands[1] != 0)
 | 
					        if (insn.operands[1] != 0)
 | 
				
			||||||
            print("{}.u32 + ", r(insn.operands[1]));
 | 
					            print("{}.u32 + ", r(insn.operands[1]));
 | 
				
			||||||
        println("{}.u32, {}.u64);", r(insn.operands[2]), r(insn.operands[0]));
 | 
					        println("{}.u32, {}.u64);", r(insn.operands[2]), r(insn.operands[0]));
 | 
				
			||||||
@@ -1413,7 +1420,7 @@ bool Recompiler::Recompile(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    case PPC_INST_STFD:
 | 
					    case PPC_INST_STFD:
 | 
				
			||||||
        printSetFlushMode(false);
 | 
					        printSetFlushMode(false);
 | 
				
			||||||
        print("\tPPC_STORE_U64(");
 | 
					        print("{}", mmioStore() ? "\tPPC_MM_STORE_U64(" : "\tPPC_STORE_U64(");
 | 
				
			||||||
        if (insn.operands[2] != 0)
 | 
					        if (insn.operands[2] != 0)
 | 
				
			||||||
            print("{}.u32 + ", r(insn.operands[2]));
 | 
					            print("{}.u32 + ", r(insn.operands[2]));
 | 
				
			||||||
        println("{}, {}.u64);", int32_t(insn.operands[1]), f(insn.operands[0]));
 | 
					        println("{}, {}.u64);", int32_t(insn.operands[1]), f(insn.operands[0]));
 | 
				
			||||||
@@ -1421,7 +1428,7 @@ bool Recompiler::Recompile(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    case PPC_INST_STFDX:
 | 
					    case PPC_INST_STFDX:
 | 
				
			||||||
        printSetFlushMode(false);
 | 
					        printSetFlushMode(false);
 | 
				
			||||||
        print("\tPPC_STORE_U64(");
 | 
					        print("{}", mmioStore() ? "\tPPC_MM_STORE_U64(" : "\tPPC_STORE_U64(");
 | 
				
			||||||
        if (insn.operands[1] != 0)
 | 
					        if (insn.operands[1] != 0)
 | 
				
			||||||
            print("{}.u32 + ", r(insn.operands[1]));
 | 
					            print("{}.u32 + ", r(insn.operands[1]));
 | 
				
			||||||
        println("{}.u32, {}.u64);", r(insn.operands[2]), f(insn.operands[0]));
 | 
					        println("{}.u32, {}.u64);", r(insn.operands[2]), f(insn.operands[0]));
 | 
				
			||||||
@@ -1429,7 +1436,7 @@ bool Recompiler::Recompile(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    case PPC_INST_STFIWX:
 | 
					    case PPC_INST_STFIWX:
 | 
				
			||||||
        printSetFlushMode(false);
 | 
					        printSetFlushMode(false);
 | 
				
			||||||
        print("\tPPC_STORE_U32(");
 | 
					        print("{}", mmioStore() ? "\tPPC_MM_STORE_U32(" : "\tPPC_STORE_U32(");
 | 
				
			||||||
        if (insn.operands[1] != 0)
 | 
					        if (insn.operands[1] != 0)
 | 
				
			||||||
            print("{}.u32 + ", r(insn.operands[1]));
 | 
					            print("{}.u32 + ", r(insn.operands[1]));
 | 
				
			||||||
        println("{}.u32, {}.u32);", r(insn.operands[2]), f(insn.operands[0]));
 | 
					        println("{}.u32, {}.u32);", r(insn.operands[2]), f(insn.operands[0]));
 | 
				
			||||||
@@ -1438,7 +1445,7 @@ bool Recompiler::Recompile(
 | 
				
			|||||||
    case PPC_INST_STFS:
 | 
					    case PPC_INST_STFS:
 | 
				
			||||||
        printSetFlushMode(false);
 | 
					        printSetFlushMode(false);
 | 
				
			||||||
        println("\t{}.f32 = float({}.f64);", temp(), f(insn.operands[0]));
 | 
					        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)
 | 
					        if (insn.operands[2] != 0)
 | 
				
			||||||
            print("{}.u32 + ", r(insn.operands[2]));
 | 
					            print("{}.u32 + ", r(insn.operands[2]));
 | 
				
			||||||
        println("{}, {}.u32);", int32_t(insn.operands[1]), temp());
 | 
					        println("{}, {}.u32);", int32_t(insn.operands[1]), temp());
 | 
				
			||||||
@@ -1447,28 +1454,28 @@ bool Recompiler::Recompile(
 | 
				
			|||||||
    case PPC_INST_STFSX:
 | 
					    case PPC_INST_STFSX:
 | 
				
			||||||
        printSetFlushMode(false);
 | 
					        printSetFlushMode(false);
 | 
				
			||||||
        println("\t{}.f32 = float({}.f64);", temp(), f(insn.operands[0]));
 | 
					        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)
 | 
					        if (insn.operands[1] != 0)
 | 
				
			||||||
            print("{}.u32 + ", r(insn.operands[1]));
 | 
					            print("{}.u32 + ", r(insn.operands[1]));
 | 
				
			||||||
        println("{}.u32, {}.u32);", r(insn.operands[2]), temp());
 | 
					        println("{}.u32, {}.u32);", r(insn.operands[2]), temp());
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case PPC_INST_STH:
 | 
					    case PPC_INST_STH:
 | 
				
			||||||
        print("\tPPC_STORE_U16(");
 | 
					        print("{}", mmioStore() ? "\tPPC_MM_STORE_U16(" : "\tPPC_STORE_U16(");
 | 
				
			||||||
        if (insn.operands[2] != 0)
 | 
					        if (insn.operands[2] != 0)
 | 
				
			||||||
            print("{}.u32 + ", r(insn.operands[2]));
 | 
					            print("{}.u32 + ", r(insn.operands[2]));
 | 
				
			||||||
        println("{}, {}.u16);", int32_t(insn.operands[1]), r(insn.operands[0]));
 | 
					        println("{}, {}.u16);", int32_t(insn.operands[1]), r(insn.operands[0]));
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case PPC_INST_STHBRX:
 | 
					    case PPC_INST_STHBRX:
 | 
				
			||||||
        print("\tPPC_STORE_U16(");
 | 
					        print("{}", mmioStore() ? "\tPPC_MM_STORE_U16(" : "\tPPC_STORE_U16(");
 | 
				
			||||||
        if (insn.operands[1] != 0)
 | 
					        if (insn.operands[1] != 0)
 | 
				
			||||||
            print("{}.u32 + ", r(insn.operands[1]));
 | 
					            print("{}.u32 + ", r(insn.operands[1]));
 | 
				
			||||||
        println("{}.u32, __builtin_bswap16({}.u16));", r(insn.operands[2]), r(insn.operands[0]));
 | 
					        println("{}.u32, __builtin_bswap16({}.u16));", r(insn.operands[2]), r(insn.operands[0]));
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case PPC_INST_STHX:
 | 
					    case PPC_INST_STHX:
 | 
				
			||||||
        print("\tPPC_STORE_U16(");
 | 
					        print("{}", mmioStore() ? "\tPPC_MM_STORE_U16(" : "\tPPC_STORE_U16(");
 | 
				
			||||||
        if (insn.operands[1] != 0)
 | 
					        if (insn.operands[1] != 0)
 | 
				
			||||||
            print("{}.u32 + ", r(insn.operands[1]));
 | 
					            print("{}.u32 + ", r(insn.operands[1]));
 | 
				
			||||||
        println("{}.u32, {}.u16);", r(insn.operands[2]), r(insn.operands[0]));
 | 
					        println("{}.u32, {}.u16);", r(insn.operands[2]), r(insn.operands[0]));
 | 
				
			||||||
@@ -1530,14 +1537,14 @@ bool Recompiler::Recompile(
 | 
				
			|||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case PPC_INST_STW:
 | 
					    case PPC_INST_STW:
 | 
				
			||||||
        print("\tPPC_STORE_U32(");
 | 
					        print("{}", mmioStore() ? "\tPPC_MM_STORE_U32(" : "\tPPC_STORE_U32(");
 | 
				
			||||||
        if (insn.operands[2] != 0)
 | 
					        if (insn.operands[2] != 0)
 | 
				
			||||||
            print("{}.u32 + ", r(insn.operands[2]));
 | 
					            print("{}.u32 + ", r(insn.operands[2]));
 | 
				
			||||||
        println("{}, {}.u32);", int32_t(insn.operands[1]), r(insn.operands[0]));
 | 
					        println("{}, {}.u32);", int32_t(insn.operands[1]), r(insn.operands[0]));
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case PPC_INST_STWBRX:
 | 
					    case PPC_INST_STWBRX:
 | 
				
			||||||
        print("\tPPC_STORE_U32(");
 | 
					        print("{}", mmioStore() ? "\tPPC_MM_STORE_U32(" : "\tPPC_STORE_U32(");
 | 
				
			||||||
        if (insn.operands[1] != 0)
 | 
					        if (insn.operands[1] != 0)
 | 
				
			||||||
            print("{}.u32 + ", r(insn.operands[1]));
 | 
					            print("{}.u32 + ", r(insn.operands[1]));
 | 
				
			||||||
        println("{}.u32, __builtin_bswap32({}.u32));", r(insn.operands[2]), r(insn.operands[0]));
 | 
					        println("{}.u32, __builtin_bswap32({}.u32));", r(insn.operands[2]), r(insn.operands[0]));
 | 
				
			||||||
@@ -1566,7 +1573,7 @@ bool Recompiler::Recompile(
 | 
				
			|||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case PPC_INST_STWX:
 | 
					    case PPC_INST_STWX:
 | 
				
			||||||
        print("\tPPC_STORE_U32(");
 | 
					        print("{}", mmioStore() ? "\tPPC_MM_STORE_U32(" : "\tPPC_STORE_U32(");
 | 
				
			||||||
        if (insn.operands[1] != 0)
 | 
					        if (insn.operands[1] != 0)
 | 
				
			||||||
            print("{}.u32 + ", r(insn.operands[1]));
 | 
					            print("{}.u32 + ", r(insn.operands[1]));
 | 
				
			||||||
        println("{}.u32, {}.u32);", r(insn.operands[2]), r(insn.operands[0]));
 | 
					        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())
 | 
					            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);
 | 
					                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);
 | 
					                std::println("Unrecognized instruction at 0x{:X}: {}", base, insn.opcode->name);
 | 
				
			||||||
                allRecompiled = false;
 | 
					                allRecompiled = false;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,6 +27,8 @@ enum class CSRState
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
struct Recompiler
 | 
					struct Recompiler
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    // Enforce In-order Execution of I/O constant for quick comparison
 | 
				
			||||||
 | 
					    static constexpr uint32_t c_eieio = 0xAC06007C;
 | 
				
			||||||
    Image image;
 | 
					    Image image;
 | 
				
			||||||
    std::vector<Function> functions;
 | 
					    std::vector<Function> functions;
 | 
				
			||||||
    std::string out;
 | 
					    std::string out;
 | 
				
			||||||
@@ -55,6 +57,7 @@ struct Recompiler
 | 
				
			|||||||
        const Function& fn,
 | 
					        const Function& fn,
 | 
				
			||||||
        uint32_t base,
 | 
					        uint32_t base,
 | 
				
			||||||
        const ppc_insn& insn,
 | 
					        const ppc_insn& insn,
 | 
				
			||||||
 | 
					        const uint32_t* data,
 | 
				
			||||||
        std::unordered_map<uint32_t, RecompilerSwitchTable>::iterator& switchTable,
 | 
					        std::unordered_map<uint32_t, RecompilerSwitchTable>::iterator& switchTable,
 | 
				
			||||||
        RecompilerLocalVariables& localVariables,
 | 
					        RecompilerLocalVariables& localVariables,
 | 
				
			||||||
        CSRState& csrState);
 | 
					        CSRState& csrState);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,11 +29,27 @@
 | 
				
			|||||||
#define PPC_LOAD_U32(x) __builtin_bswap32(*(volatile uint32_t*)(base + (x)))
 | 
					#define PPC_LOAD_U32(x) __builtin_bswap32(*(volatile uint32_t*)(base + (x)))
 | 
				
			||||||
#define PPC_LOAD_U64(x) __builtin_bswap64(*(volatile uint64_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_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_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_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)
 | 
					#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_FUNC(x) x(ctx, base)
 | 
				
			||||||
#define PPC_CALL_INDIRECT_FUNC(x) (*(PPCFunc**)(ctx.fn + uint64_t(x) * 2))(ctx, base)
 | 
					#define PPC_CALL_INDIRECT_FUNC(x) (*(PPCFunc**)(ctx.fn + uint64_t(x) * 2))(ctx, base)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user