diff --git a/include/dynarmic/callbacks.h b/include/dynarmic/callbacks.h index 3eb58f6a..d40e881f 100644 --- a/include/dynarmic/callbacks.h +++ b/include/dynarmic/callbacks.h @@ -16,6 +16,10 @@ class Jit; /// These function pointers may be inserted into compiled code. struct UserCallbacks { + // All reads through this callback are 4-byte aligned. + // Memory must be interpreted as little endian. + std::uint32_t (*MemoryReadCode)(std::uint32_t vaddr); + // Reads through these callbacks may not be aligned. // Memory must be interpreted as if ENDIANSTATE == 0, endianness will be corrected by the JIT. std::uint8_t (*MemoryRead8)(std::uint32_t vaddr); diff --git a/src/backend_x64/interface_x64.cpp b/src/backend_x64/interface_x64.cpp index 8655bbd5..84c00a16 100644 --- a/src/backend_x64/interface_x64.cpp +++ b/src/backend_x64/interface_x64.cpp @@ -103,7 +103,7 @@ private: if (block) return *block; - IR::Block ir_block = Arm::Translate(descriptor, callbacks.MemoryRead32); + IR::Block ir_block = Arm::Translate(descriptor, callbacks.MemoryReadCode); Optimization::GetSetElimination(ir_block); Optimization::DeadCodeElimination(ir_block); Optimization::VerificationPass(ir_block); diff --git a/src/frontend/translate/translate.cpp b/src/frontend/translate/translate.cpp index af288ab8..57ee49f4 100644 --- a/src/frontend/translate/translate.cpp +++ b/src/frontend/translate/translate.cpp @@ -11,11 +11,11 @@ namespace Dynarmic { namespace Arm { -IR::Block TranslateArm(IR::LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32); -IR::Block TranslateThumb(IR::LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32); +IR::Block TranslateArm(IR::LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code); +IR::Block TranslateThumb(IR::LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code); -IR::Block Translate(IR::LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32) { - return (descriptor.TFlag() ? TranslateThumb : TranslateArm)(descriptor, memory_read_32); +IR::Block Translate(IR::LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code) { + return (descriptor.TFlag() ? TranslateThumb : TranslateArm)(descriptor, memory_read_code); } } // namespace Arm diff --git a/src/frontend/translate/translate.h b/src/frontend/translate/translate.h index 05f7fadd..816d46fe 100644 --- a/src/frontend/translate/translate.h +++ b/src/frontend/translate/translate.h @@ -18,15 +18,15 @@ namespace Arm { struct LocationDescriptor; -using MemoryRead32FuncType = u32 (*)(u32 vaddr); +using MemoryReadCodeFuncType = u32 (*)(u32 vaddr); /** * This function translates instructions in memory into our intermediate representation. * @param descriptor The starting location of the basic block. Includes information like PC, Thumb state, &c. - * @param memory_read_32 The function we should use to read emulated memory. + * @param memory_read_code The function we should use to read emulated memory. * @return A translated basic block in the intermediate representation. */ -IR::Block Translate(IR::LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32); +IR::Block Translate(IR::LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code); } // namespace Arm } // namespace Dynarmic diff --git a/src/frontend/translate/translate_arm.cpp b/src/frontend/translate/translate_arm.cpp index 5deba292..77774dea 100644 --- a/src/frontend/translate/translate_arm.cpp +++ b/src/frontend/translate/translate_arm.cpp @@ -28,13 +28,13 @@ static bool CondCanContinue(ConditionalState cond_state, const IR::IREmitter& ir return std::all_of(ir.block.begin(), ir.block.end(), [](const IR::Inst& inst) { return !inst.WritesToCPSR(); }); } -IR::Block TranslateArm(IR::LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32) { +IR::Block TranslateArm(IR::LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code) { ArmTranslatorVisitor visitor{descriptor}; bool should_continue = true; while (should_continue && CondCanContinue(visitor.cond_state, visitor.ir)) { const u32 arm_pc = visitor.ir.current_location.PC(); - const u32 arm_instruction = memory_read_32(arm_pc); + const u32 arm_instruction = memory_read_code(arm_pc); if (auto vfp_decoder = DecodeVFP2(arm_instruction)) { should_continue = vfp_decoder->call(visitor, arm_instruction); diff --git a/src/frontend/translate/translate_thumb.cpp b/src/frontend/translate/translate_thumb.cpp index 908392cc..c79b745d 100644 --- a/src/frontend/translate/translate_thumb.cpp +++ b/src/frontend/translate/translate_thumb.cpp @@ -836,8 +836,8 @@ enum class ThumbInstSize { Thumb16, Thumb32 }; -std::tuple ReadThumbInstruction(u32 arm_pc, MemoryRead32FuncType memory_read_32) { - u32 first_part = memory_read_32(arm_pc & 0xFFFFFFFC); +std::tuple ReadThumbInstruction(u32 arm_pc, MemoryReadCodeFuncType memory_read_code) { + u32 first_part = memory_read_code(arm_pc & 0xFFFFFFFC); if ((arm_pc & 0x2) != 0) first_part >>= 16; first_part &= 0xFFFF; @@ -850,7 +850,7 @@ std::tuple ReadThumbInstruction(u32 arm_pc, MemoryRead32Func // 32-bit thumb instruction // These always start with 0b11101, 0b11110 or 0b11111. - u32 second_part = memory_read_32((arm_pc + 2) & 0xFFFFFFFC); + u32 second_part = memory_read_code((arm_pc + 2) & 0xFFFFFFFC); if (((arm_pc + 2) & 0x2) != 0) second_part >>= 16; second_part &= 0xFFFF; @@ -860,7 +860,7 @@ std::tuple ReadThumbInstruction(u32 arm_pc, MemoryRead32Func } // local namespace -IR::Block TranslateThumb(IR::LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32) { +IR::Block TranslateThumb(IR::LocationDescriptor descriptor, MemoryReadCodeFuncType memory_read_code) { ThumbTranslatorVisitor visitor{descriptor}; bool should_continue = true; @@ -869,7 +869,7 @@ IR::Block TranslateThumb(IR::LocationDescriptor descriptor, MemoryRead32FuncType u32 thumb_instruction; ThumbInstSize inst_size; - std::tie(thumb_instruction, inst_size) = ReadThumbInstruction(arm_pc, memory_read_32); + std::tie(thumb_instruction, inst_size) = ReadThumbInstruction(arm_pc, memory_read_code); if (inst_size == ThumbInstSize::Thumb16) { auto decoder = DecodeThumb16(static_cast(thumb_instruction)); diff --git a/tests/arm/fuzz_arm.cpp b/tests/arm/fuzz_arm.cpp index e9090955..ef8634a0 100644 --- a/tests/arm/fuzz_arm.cpp +++ b/tests/arm/fuzz_arm.cpp @@ -52,6 +52,7 @@ static u8 MemoryRead8(u32 vaddr); static u16 MemoryRead16(u32 vaddr); static u32 MemoryRead32(u32 vaddr); static u64 MemoryRead64(u32 vaddr); +static u32 MemoryReadCode(u32 vaddr); static void MemoryWrite8(u32 vaddr, u8 value); static void MemoryWrite16(u32 vaddr, u16 value); static void MemoryWrite32(u32 vaddr, u32 value); @@ -69,15 +70,18 @@ static u16 MemoryRead16(u32 vaddr) { return static_cast(vaddr); } static u32 MemoryRead32(u32 vaddr) { - if (vaddr < code_mem.size() * sizeof(u32)) { - size_t index = vaddr / sizeof(u32); - return code_mem[index]; - } return vaddr; } static u64 MemoryRead64(u32 vaddr) { return MemoryRead32(vaddr) | (u64(MemoryRead32(vaddr+4)) << 32); } +static u32 MemoryReadCode(u32 vaddr) { + if (vaddr < code_mem.size() * sizeof(u32)) { + size_t index = vaddr / sizeof(u32); + return code_mem[index]; + } + return 0xeafffffe; // b +#0 +} static void MemoryWrite8(u32 vaddr, u8 value){ write_records.push_back({8, vaddr, value}); @@ -128,6 +132,7 @@ static Dynarmic::UserCallbacks GetUserCallbacks() { user_callbacks.MemoryRead16 = &MemoryRead16; user_callbacks.MemoryRead32 = &MemoryRead32; user_callbacks.MemoryRead64 = &MemoryRead64; + user_callbacks.MemoryReadCode = &MemoryReadCode; user_callbacks.MemoryWrite8 = &MemoryWrite8; user_callbacks.MemoryWrite16 = &MemoryWrite16; user_callbacks.MemoryWrite32 = &MemoryWrite32; @@ -292,7 +297,7 @@ void FuzzJitArm(const size_t instruction_count, const size_t instructions_to_exe size_t num_insts = 0; while (num_insts < instructions_to_execute_count) { Dynarmic::IR::LocationDescriptor descriptor = {u32(num_insts * 4), Dynarmic::Arm::PSR{}, Dynarmic::Arm::FPSCR{}}; - Dynarmic::IR::Block ir_block = Dynarmic::Arm::Translate(descriptor, &MemoryRead32); + Dynarmic::IR::Block ir_block = Dynarmic::Arm::Translate(descriptor, &MemoryReadCode); Dynarmic::Optimization::GetSetElimination(ir_block); Dynarmic::Optimization::DeadCodeElimination(ir_block); Dynarmic::Optimization::VerificationPass(ir_block); diff --git a/tests/arm/fuzz_thumb.cpp b/tests/arm/fuzz_thumb.cpp index d7f92e20..38f4db0e 100644 --- a/tests/arm/fuzz_thumb.cpp +++ b/tests/arm/fuzz_thumb.cpp @@ -70,6 +70,13 @@ static u32 MemoryRead32(u32 vaddr) { static u64 MemoryRead64(u32 vaddr) { return vaddr; } +static u32 MemoryReadCode(u32 vaddr) { + if (vaddr < code_mem.size() * sizeof(u16)) { + size_t index = vaddr / sizeof(u16); + return code_mem[index] | (code_mem[index + 1] << 16); + } + return 0xE7FEE7FE; // b +#0, b +#0 +} static void MemoryWrite8(u32 vaddr, u8 value){ write_records.push_back({8, vaddr, value}); @@ -116,6 +123,7 @@ static Dynarmic::UserCallbacks GetUserCallbacks() { user_callbacks.MemoryRead16 = &MemoryRead16; user_callbacks.MemoryRead32 = &MemoryRead32; user_callbacks.MemoryRead64 = &MemoryRead64; + user_callbacks.MemoryReadCode = &MemoryReadCode; user_callbacks.MemoryWrite8 = &MemoryWrite8; user_callbacks.MemoryWrite16 = &MemoryWrite16; user_callbacks.MemoryWrite32 = &MemoryWrite32; @@ -247,7 +255,7 @@ void FuzzJitThumb(const size_t instruction_count, const size_t instructions_to_e Dynarmic::Arm::PSR cpsr; cpsr.T(true); - Dynarmic::IR::Block ir_block = Dynarmic::Arm::Translate({0, cpsr, Dynarmic::Arm::FPSCR{}}, MemoryRead32); + Dynarmic::IR::Block ir_block = Dynarmic::Arm::Translate({0, cpsr, Dynarmic::Arm::FPSCR{}}, MemoryReadCode); Dynarmic::Optimization::GetSetElimination(ir_block); Dynarmic::Optimization::DeadCodeElimination(ir_block); Dynarmic::Optimization::VerificationPass(ir_block); diff --git a/tests/arm/test_thumb_instructions.cpp b/tests/arm/test_thumb_instructions.cpp index 8a238ff4..6f992d58 100644 --- a/tests/arm/test_thumb_instructions.cpp +++ b/tests/arm/test_thumb_instructions.cpp @@ -15,15 +15,19 @@ static std::array code_mem{}; static u32 MemoryRead32(u32 vaddr); +static u32 MemoryReadCode(u32 vaddr); static void InterpreterFallback(u32 pc, Dynarmic::Jit* jit, void*); static Dynarmic::UserCallbacks GetUserCallbacks(); static u32 MemoryRead32(u32 vaddr) { + return vaddr; +} +static u32 MemoryReadCode(u32 vaddr) { if (vaddr < code_mem.size() * sizeof(u16)) { size_t index = vaddr / sizeof(u16); return code_mem[index] | (code_mem[index+1] << 16); } - return vaddr; + return 0xE7FEE7FE; //b +#0, b +#0 } static void InterpreterFallback(u32 pc, Dynarmic::Jit* jit, void*) { @@ -45,6 +49,7 @@ static void InterpreterFallback(u32 pc, Dynarmic::Jit* jit, void*) { static Dynarmic::UserCallbacks GetUserCallbacks() { Dynarmic::UserCallbacks user_callbacks{}; user_callbacks.MemoryRead32 = &MemoryRead32; + user_callbacks.MemoryReadCode = &MemoryReadCode; user_callbacks.InterpreterFallback = &InterpreterFallback; return user_callbacks; } diff --git a/tests/skyeye_interpreter/dyncom/arm_dyncom_interpreter.cpp b/tests/skyeye_interpreter/dyncom/arm_dyncom_interpreter.cpp index 531de758..3c12697e 100644 --- a/tests/skyeye_interpreter/dyncom/arm_dyncom_interpreter.cpp +++ b/tests/skyeye_interpreter/dyncom/arm_dyncom_interpreter.cpp @@ -803,7 +803,7 @@ enum { static unsigned int InterpreterTranslateInstruction(const ARMul_State* cpu, const u32 phys_addr, ARM_INST_PTR& inst_base) { unsigned int inst_size = 4; - unsigned int inst = (*cpu->user_callbacks.MemoryRead32)(phys_addr & 0xFFFFFFFC); + unsigned int inst = (*cpu->user_callbacks.MemoryReadCode)(phys_addr & 0xFFFFFFFC); // If we are in Thumb mode, we'll translate one Thumb instruction to the corresponding ARM instruction if (cpu->TFlag) {