fuzz_arm: Test MSR and MRS instructions against unicorn

* Add always_little_endian option to mach unicorn behavior.
* Correct CPSR.Mode = Usermode
This commit is contained in:
MerryMage 2019-07-27 19:54:57 +01:00
parent 39ab7cb643
commit c7d20f3f2f
4 changed files with 35 additions and 13 deletions

View file

@ -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

View file

@ -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<u32>(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<u32>(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)) {

View file

@ -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;

View file

@ -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<u32>(0, 0xF) << 28) | 0x13;
const u32 cpsr = (RandInt<u32>(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<u32>(0, 0xF) << 28) | 0x13;
const u32 cpsr = (RandInt<u32>(0, 0xF) << 28) | 0x10;
const u32 fpcr = RandomFpcr();
INFO("Instruction 1: 0x" << std::hex << instructions[0]);