diff --git a/qemu/target/mips/cpu.c b/qemu/target/mips/cpu.c index 640c8c9b..ac2a6145 100644 --- a/qemu/target/mips/cpu.c +++ b/qemu/target/mips/cpu.c @@ -194,7 +194,12 @@ MIPSCPU *cpu_mips_init(struct uc_struct *uc) mips_cpu_initfn(uc, cs); env = &cpu->env; - env->cpu_model = &(mips_defs[uc->cpu_model]); + if(uc->mode & UC_MODE_MIPS64){ + // 64-bit CPU models are defined in the array directly after 32-bit models + env->cpu_model = &(mips_defs[uc->cpu_model + UC_CPU_MIPS32_ENDING]); + } else { + env->cpu_model = &(mips_defs[uc->cpu_model]); + } if (env->cpu_model == NULL) { free(cpu); diff --git a/tests/regress/mips64.py b/tests/regress/mips64.py new file mode 100644 index 00000000..c0e034e9 --- /dev/null +++ b/tests/regress/mips64.py @@ -0,0 +1,39 @@ +import sys +import unittest +import regress +from unicorn import * +from unicorn.mips_const import * + + +class Mips64(regress.RegressTest): + + @unittest.skipIf(sys.version_info < (3, 7), reason="requires python3.7 or higher") + def runTest(self): + # Two instructions: + # daddu $gp, $gp, $ra # a 64-bit instruction. This is important - it ensures the selected CPU model is 64-bit, otherwise it would crash + # move $t1, $v0 + + code = b"\x03\x9f\xe0\x2d" + b"\x00\x40\x48\x25" + + uc = Uc(UC_ARCH_MIPS, UC_MODE_MIPS64 + UC_MODE_BIG_ENDIAN) + # For MIPS64 to be able to reference addresses >= 0x80000000, you need to enable the virtual TLB + # See https://github.com/unicorn-engine/unicorn/pull/2111 for more details + uc.ctl_set_tlb_mode(UC_TLB_VIRTUAL) + + ADDRESS = 0x0120003000 + + uc.reg_write(UC_MIPS_REG_PC, ADDRESS) + uc.reg_write(UC_MIPS_REG_GP, 0x123) + uc.reg_write(UC_MIPS_REG_RA, 0x456) + + uc.mem_map(ADDRESS, 4 * 1024) + uc.mem_write(ADDRESS, code) + + # This will raise an exception if MIPS64 fails + uc.emu_start(ADDRESS, 0, count=2) + + self.assertEqual(uc.reg_read(UC_MIPS_REG_PC),0x0120003000 + 8) + + +if __name__ == '__main__': + regress.main() diff --git a/uc.c b/uc.c index 52ce2227..3cd43152 100644 --- a/uc.c +++ b/uc.c @@ -1020,8 +1020,11 @@ uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until, #endif #ifdef UNICORN_HAS_MIPS case UC_ARCH_MIPS: - // TODO: MIPS32/MIPS64/BIGENDIAN etc - uc_reg_write(uc, UC_MIPS_REG_PC, &begin_pc32); + if (uc->mode & UC_MODE_MIPS64) { + uc_reg_write(uc, UC_MIPS_REG_PC, &begin); + } else { + uc_reg_write(uc, UC_MIPS_REG_PC, &begin_pc32); + } break; #endif #ifdef UNICORN_HAS_SPARC