From c7d20f3f2fcde764f24560631f1dcb0965419d3a Mon Sep 17 00:00:00 2001 From: MerryMage Date: Sat, 27 Jul 2019 19:54:57 +0100 Subject: [PATCH] fuzz_arm: Test MSR and MRS instructions against unicorn * Add always_little_endian option to mach unicorn behavior. * Correct CPSR.Mode = Usermode --- include/dynarmic/A32/config.h | 6 ++++++ src/backend/x64/a32_emit_x64.cpp | 33 ++++++++++++++++++++++++-------- src/backend/x64/a32_emit_x64.h | 1 + tests/A32/fuzz_arm.cpp | 8 +++----- 4 files changed, 35 insertions(+), 13 deletions(-) diff --git a/include/dynarmic/A32/config.h b/include/dynarmic/A32/config.h index 54c96be7..ea639bfe 100644 --- a/include/dynarmic/A32/config.h +++ b/include/dynarmic/A32/config.h @@ -108,6 +108,12 @@ struct UserConfig { /// This enables the fast dispatcher. bool enable_fast_dispatch = true; + + /// This option relates to the CPSR.E flag. Enabling this option disables modification + /// of CPSR.E by the emulated program, forcing it to 0. + /// NOTE: Calling Jit::SetCpsr with CPSR.E=1 while this option is enabled may result + /// in unusual behavior. + bool always_little_endian = false; }; } // namespace A32 diff --git a/src/backend/x64/a32_emit_x64.cpp b/src/backend/x64/a32_emit_x64.cpp index 018e70ea..bff491fa 100644 --- a/src/backend/x64/a32_emit_x64.cpp +++ b/src/backend/x64/a32_emit_x64.cpp @@ -381,6 +381,10 @@ void A32EmitX64::EmitA32SetCpsr(A32EmitContext& ctx, IR::Inst* inst) { const Xbyak::Reg32 tmp = ctx.reg_alloc.ScratchGpr().cvt32(); const Xbyak::Reg32 tmp2 = ctx.reg_alloc.ScratchGpr().cvt32(); + if (config.always_little_endian) { + code.and_(cpsr, 0xFFFFFDFF); + } + // cpsr_q code.bt(cpsr, 27); code.setc(code.byte[r15 + offsetof(A32JitState, cpsr_q)]); @@ -412,6 +416,11 @@ void A32EmitX64::EmitA32SetCpsr(A32EmitContext& ctx, IR::Inst* inst) { code.or_(qword[r15 + offsetof(A32JitState, upper_location_descriptor)], tmp.cvt64()); } else { ctx.reg_alloc.HostCall(nullptr, args[0]); + + if (config.always_little_endian) { + code.and_(code.ABI_PARAM1, 0xFFFFFDFF); + } + code.mov(code.ABI_PARAM2, code.r15); code.CallFunction(&SetCpsrImpl); } @@ -1249,14 +1258,24 @@ void A32EmitX64::EmitTerminalImpl(IR::Term::ReturnToDispatch, IR::LocationDescri code.ReturnFromRunCode(); } -static u32 CalculateUpper(const IR::LocationDescriptor& arg) { - return static_cast(arg.Value() >> 32); +void A32EmitX64::EmitSetUpperLocationDescriptor(IR::LocationDescriptor new_location, IR::LocationDescriptor old_location) { + auto get_upper = [](const IR::LocationDescriptor& desc) -> u32 { + return static_cast(desc.Value() >> 32); + }; + + const u32 old_upper = get_upper(old_location); + const u32 new_upper = [&]{ + const u32 mask = ~u32(config.always_little_endian ? 0x2 : 0); + return get_upper(new_location) & mask; + }(); + + if (old_upper != new_upper) { + code.mov(dword[r15 + offsetof(A32JitState, upper_location_descriptor)], new_upper); + } } void A32EmitX64::EmitTerminalImpl(IR::Term::LinkBlock terminal, IR::LocationDescriptor initial_location) { - if (CalculateUpper(terminal.next) != CalculateUpper(initial_location)) { - code.mov(dword[r15 + offsetof(A32JitState, upper_location_descriptor)], CalculateUpper(terminal.next)); - } + EmitSetUpperLocationDescriptor(terminal.next, initial_location); code.cmp(qword[r15 + offsetof(A32JitState, cycles_remaining)], 0); @@ -1279,9 +1298,7 @@ void A32EmitX64::EmitTerminalImpl(IR::Term::LinkBlock terminal, IR::LocationDesc } void A32EmitX64::EmitTerminalImpl(IR::Term::LinkBlockFast terminal, IR::LocationDescriptor initial_location) { - if (CalculateUpper(terminal.next) != CalculateUpper(initial_location)) { - code.mov(dword[r15 + offsetof(A32JitState, upper_location_descriptor)], CalculateUpper(terminal.next)); - } + EmitSetUpperLocationDescriptor(terminal.next, initial_location); patch_information[terminal.next].jmp.emplace_back(code.getCurr()); if (const auto next_bb = GetBasicBlock(terminal.next)) { diff --git a/src/backend/x64/a32_emit_x64.h b/src/backend/x64/a32_emit_x64.h index 24fc39a4..24f62cd9 100644 --- a/src/backend/x64/a32_emit_x64.h +++ b/src/backend/x64/a32_emit_x64.h @@ -84,6 +84,7 @@ protected: std::string LocationDescriptorToFriendlyName(const IR::LocationDescriptor&) const override; // Terminal instruction emitters + void EmitSetUpperLocationDescriptor(IR::LocationDescriptor new_location, IR::LocationDescriptor old_location); void EmitTerminalImpl(IR::Term::Interpret terminal, IR::LocationDescriptor initial_location) override; void EmitTerminalImpl(IR::Term::ReturnToDispatch terminal, IR::LocationDescriptor initial_location) override; void EmitTerminalImpl(IR::Term::LinkBlock terminal, IR::LocationDescriptor initial_location) override; diff --git a/tests/A32/fuzz_arm.cpp b/tests/A32/fuzz_arm.cpp index 7f9bcfa8..e94698b9 100644 --- a/tests/A32/fuzz_arm.cpp +++ b/tests/A32/fuzz_arm.cpp @@ -108,9 +108,6 @@ u32 GenRandomInst(u32 pc, bool is_last_inst) { "arm_CPS", "arm_RFE", "arm_SRS", // Undefined "arm_UDF", - - // Behavior differs from Qemu - "arm_MSR_reg", "arm_MSR_imm", "arm_MRS", }; for (const auto& [fn, bitstring] : list) { @@ -140,6 +137,7 @@ Dynarmic::A32::UserConfig GetUserConfig(ArmTestEnv& testenv) { Dynarmic::A32::UserConfig user_config; user_config.enable_fast_dispatch = false; user_config.callbacks = &testenv; + user_config.always_little_endian = true; return user_config; } @@ -287,7 +285,7 @@ TEST_CASE("A32: Single random instruction", "[arm]") { instructions[0] = GenRandomInst(0, true); const u32 start_address = 100; - const u32 cpsr = (RandInt(0, 0xF) << 28) | 0x13; + const u32 cpsr = (RandInt(0, 0xF) << 28) | 0x10; const u32 fpcr = RandomFpcr(); INFO("Instruction: 0x" << std::hex << instructions[0]); @@ -319,7 +317,7 @@ TEST_CASE("A32: Small random block", "[arm]") { instructions[4] = GenRandomInst(16, true); const u32 start_address = 100; - const u32 cpsr = (RandInt(0, 0xF) << 28) | 0x13; + const u32 cpsr = (RandInt(0, 0xF) << 28) | 0x10; const u32 fpcr = RandomFpcr(); INFO("Instruction 1: 0x" << std::hex << instructions[0]);