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:
parent
39ab7cb643
commit
c7d20f3f2f
4 changed files with 35 additions and 13 deletions
|
@ -108,6 +108,12 @@ struct UserConfig {
|
||||||
|
|
||||||
/// This enables the fast dispatcher.
|
/// This enables the fast dispatcher.
|
||||||
bool enable_fast_dispatch = true;
|
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
|
} // namespace A32
|
||||||
|
|
|
@ -381,6 +381,10 @@ void A32EmitX64::EmitA32SetCpsr(A32EmitContext& ctx, IR::Inst* inst) {
|
||||||
const Xbyak::Reg32 tmp = ctx.reg_alloc.ScratchGpr().cvt32();
|
const Xbyak::Reg32 tmp = ctx.reg_alloc.ScratchGpr().cvt32();
|
||||||
const Xbyak::Reg32 tmp2 = 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
|
// cpsr_q
|
||||||
code.bt(cpsr, 27);
|
code.bt(cpsr, 27);
|
||||||
code.setc(code.byte[r15 + offsetof(A32JitState, cpsr_q)]);
|
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());
|
code.or_(qword[r15 + offsetof(A32JitState, upper_location_descriptor)], tmp.cvt64());
|
||||||
} else {
|
} else {
|
||||||
ctx.reg_alloc.HostCall(nullptr, args[0]);
|
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.mov(code.ABI_PARAM2, code.r15);
|
||||||
code.CallFunction(&SetCpsrImpl);
|
code.CallFunction(&SetCpsrImpl);
|
||||||
}
|
}
|
||||||
|
@ -1249,14 +1258,24 @@ void A32EmitX64::EmitTerminalImpl(IR::Term::ReturnToDispatch, IR::LocationDescri
|
||||||
code.ReturnFromRunCode();
|
code.ReturnFromRunCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 CalculateUpper(const IR::LocationDescriptor& arg) {
|
void A32EmitX64::EmitSetUpperLocationDescriptor(IR::LocationDescriptor new_location, IR::LocationDescriptor old_location) {
|
||||||
return static_cast<u32>(arg.Value() >> 32);
|
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) {
|
void A32EmitX64::EmitTerminalImpl(IR::Term::LinkBlock terminal, IR::LocationDescriptor initial_location) {
|
||||||
if (CalculateUpper(terminal.next) != CalculateUpper(initial_location)) {
|
EmitSetUpperLocationDescriptor(terminal.next, initial_location);
|
||||||
code.mov(dword[r15 + offsetof(A32JitState, upper_location_descriptor)], CalculateUpper(terminal.next));
|
|
||||||
}
|
|
||||||
|
|
||||||
code.cmp(qword[r15 + offsetof(A32JitState, cycles_remaining)], 0);
|
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) {
|
void A32EmitX64::EmitTerminalImpl(IR::Term::LinkBlockFast terminal, IR::LocationDescriptor initial_location) {
|
||||||
if (CalculateUpper(terminal.next) != CalculateUpper(initial_location)) {
|
EmitSetUpperLocationDescriptor(terminal.next, initial_location);
|
||||||
code.mov(dword[r15 + offsetof(A32JitState, upper_location_descriptor)], CalculateUpper(terminal.next));
|
|
||||||
}
|
|
||||||
|
|
||||||
patch_information[terminal.next].jmp.emplace_back(code.getCurr());
|
patch_information[terminal.next].jmp.emplace_back(code.getCurr());
|
||||||
if (const auto next_bb = GetBasicBlock(terminal.next)) {
|
if (const auto next_bb = GetBasicBlock(terminal.next)) {
|
||||||
|
|
|
@ -84,6 +84,7 @@ protected:
|
||||||
std::string LocationDescriptorToFriendlyName(const IR::LocationDescriptor&) const override;
|
std::string LocationDescriptorToFriendlyName(const IR::LocationDescriptor&) const override;
|
||||||
|
|
||||||
// Terminal instruction emitters
|
// 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::Interpret terminal, IR::LocationDescriptor initial_location) override;
|
||||||
void EmitTerminalImpl(IR::Term::ReturnToDispatch 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;
|
void EmitTerminalImpl(IR::Term::LinkBlock terminal, IR::LocationDescriptor initial_location) override;
|
||||||
|
|
|
@ -108,9 +108,6 @@ u32 GenRandomInst(u32 pc, bool is_last_inst) {
|
||||||
"arm_CPS", "arm_RFE", "arm_SRS",
|
"arm_CPS", "arm_RFE", "arm_SRS",
|
||||||
// Undefined
|
// Undefined
|
||||||
"arm_UDF",
|
"arm_UDF",
|
||||||
|
|
||||||
// Behavior differs from Qemu
|
|
||||||
"arm_MSR_reg", "arm_MSR_imm", "arm_MRS",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const auto& [fn, bitstring] : list) {
|
for (const auto& [fn, bitstring] : list) {
|
||||||
|
@ -140,6 +137,7 @@ Dynarmic::A32::UserConfig GetUserConfig(ArmTestEnv& testenv) {
|
||||||
Dynarmic::A32::UserConfig user_config;
|
Dynarmic::A32::UserConfig user_config;
|
||||||
user_config.enable_fast_dispatch = false;
|
user_config.enable_fast_dispatch = false;
|
||||||
user_config.callbacks = &testenv;
|
user_config.callbacks = &testenv;
|
||||||
|
user_config.always_little_endian = true;
|
||||||
return user_config;
|
return user_config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,7 +285,7 @@ TEST_CASE("A32: Single random instruction", "[arm]") {
|
||||||
instructions[0] = GenRandomInst(0, true);
|
instructions[0] = GenRandomInst(0, true);
|
||||||
|
|
||||||
const u32 start_address = 100;
|
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();
|
const u32 fpcr = RandomFpcr();
|
||||||
|
|
||||||
INFO("Instruction: 0x" << std::hex << instructions[0]);
|
INFO("Instruction: 0x" << std::hex << instructions[0]);
|
||||||
|
@ -319,7 +317,7 @@ TEST_CASE("A32: Small random block", "[arm]") {
|
||||||
instructions[4] = GenRandomInst(16, true);
|
instructions[4] = GenRandomInst(16, true);
|
||||||
|
|
||||||
const u32 start_address = 100;
|
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();
|
const u32 fpcr = RandomFpcr();
|
||||||
|
|
||||||
INFO("Instruction 1: 0x" << std::hex << instructions[0]);
|
INFO("Instruction 1: 0x" << std::hex << instructions[0]);
|
||||||
|
|
Loading…
Reference in a new issue