diff --git a/qemu/target/mips/unicorn.c b/qemu/target/mips/unicorn.c index ab922e6f4c..58348511b3 100644 --- a/qemu/target/mips/unicorn.c +++ b/qemu/target/mips/unicorn.c @@ -19,12 +19,18 @@ MIPSCPU *cpu_mips_init(struct uc_struct *uc); static void mips_set_pc(struct uc_struct *uc, uint64_t address) { - ((CPUMIPSState *)uc->cpu->env_ptr)->active_tc.PC = address; + ((CPUMIPSState *)uc->cpu->env_ptr)->active_tc.PC = address & ~(uint64_t )1ULL; + if (address & 1) { + ((CPUMIPSState *)uc->cpu->env_ptr)->hflags |= MIPS_HFLAG_M16; + } else { + ((CPUMIPSState *)uc->cpu->env_ptr)->hflags &= ~(MIPS_HFLAG_M16); + } } static uint64_t mips_get_pc(struct uc_struct *uc) { - return ((CPUMIPSState *)uc->cpu->env_ptr)->active_tc.PC; + return ((CPUMIPSState *)uc->cpu->env_ptr)->active_tc.PC | + !!(((CPUMIPSState *)uc->cpu->env_ptr)->hflags & (MIPS_HFLAG_M16)); } static void mips_release(void *ctx) @@ -128,7 +134,12 @@ uc_err reg_write(void *_env, int mode, unsigned int regid, const void *value, break; case UC_MIPS_REG_PC: CHECK_REG_TYPE(mipsreg_t); - env->active_tc.PC = *(mipsreg_t *)value; + env->active_tc.PC = *(mipsreg_t *)value & ~1ULL; + if ((*(uint32_t *)value & 1)) { + env->hflags |= MIPS_HFLAG_M16; + } else { + env->hflags &= ~(MIPS_HFLAG_M16); + } *setpc = 1; break; case UC_MIPS_REG_CP0_CONFIG3: diff --git a/tests/unit/test_mips.c b/tests/unit/test_mips.c index 8a00b8568c..6e9d4dd1f4 100644 --- a/tests/unit/test_mips.c +++ b/tests/unit/test_mips.c @@ -17,7 +17,7 @@ static void test_mips_el_ori(void) char code[] = "\x56\x34\x21\x34"; // ori $at, $at, 0x3456; int r_r1 = 0x6789; - uc_common_setup(&uc, UC_ARCH_MIPS, UC_MODE_32 | UC_MODE_LITTLE_ENDIAN, code, + uc_common_setup(&uc, UC_ARCH_MIPS, UC_MODE_MIPS32 | UC_MODE_LITTLE_ENDIAN, code, sizeof(code) - 1); OK(uc_reg_write(uc, UC_MIPS_REG_1, &r_r1)); @@ -36,7 +36,7 @@ static void test_mips_eb_ori(void) char code[] = "\x34\x21\x34\x56"; // ori $at, $at, 0x3456; int r_r1 = 0x6789; - uc_common_setup(&uc, UC_ARCH_MIPS, UC_MODE_32 | UC_MODE_BIG_ENDIAN, code, + uc_common_setup(&uc, UC_ARCH_MIPS, UC_MODE_MIPS32 | UC_MODE_BIG_ENDIAN, code, sizeof(code) - 1); OK(uc_reg_write(uc, UC_MIPS_REG_1, &r_r1)); @@ -56,7 +56,7 @@ static void test_mips_stop_at_branch(void) "\x02\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00"; // j 0x8; nop; int r_pc = 0x0; - uc_common_setup(&uc, UC_ARCH_MIPS, UC_MODE_32 | UC_MODE_LITTLE_ENDIAN, code, + uc_common_setup(&uc, UC_ARCH_MIPS, UC_MODE_MIPS32 | UC_MODE_LITTLE_ENDIAN, code, sizeof(code) - 1); // Execute one instruction with branch delay slot. @@ -78,7 +78,7 @@ static void test_mips_stop_at_delay_slot(void) "\x02\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00"; // j 0x8; nop; int r_pc = 0x0; - uc_common_setup(&uc, UC_ARCH_MIPS, UC_MODE_32 | UC_MODE_LITTLE_ENDIAN, code, + uc_common_setup(&uc, UC_ARCH_MIPS, UC_MODE_MIPS32 | UC_MODE_LITTLE_ENDIAN, code, sizeof(code) - 1); // Stop at the delay slot by design. @@ -99,7 +99,7 @@ static void test_mips_lwx_exception_issue_1314(void) char code[] = "\x0a\xc8\x79\x7e"; // lwx $t9, $t9($s3) int reg; - uc_common_setup(&uc, UC_ARCH_MIPS, UC_MODE_32 | UC_MODE_LITTLE_ENDIAN, code, + uc_common_setup(&uc, UC_ARCH_MIPS, UC_MODE_MIPS32 | UC_MODE_LITTLE_ENDIAN, code, sizeof(code) - 1); OK(uc_mem_map(uc, 0x10000, 0x4000, UC_PROT_ALL)); @@ -126,10 +126,31 @@ static void test_mips_lwx_exception_issue_1314(void) OK(uc_close(uc)); } +static void test_mips_mips16(void) +{ + uc_engine *uc; + char code[] = "\xC4\x6B\x49\xE3"; // li $v1, 0xC4; addu $v0, $v1, $v0 + int r_v0 = 0x6789; + int mips16_lowbit = 1; + + uc_common_setup(&uc, UC_ARCH_MIPS, UC_MODE_MIPS32 | UC_MODE_LITTLE_ENDIAN, code, + sizeof(code) - 1); + OK(uc_reg_write(uc, UC_MIPS_REG_V0, &r_v0)); + + OK(uc_emu_start(uc, code_start | mips16_lowbit, code_start + sizeof(code) - 1, 0, 0)); + + OK(uc_reg_read(uc, UC_MIPS_REG_V0, &r_v0)); + + TEST_CHECK(r_v0 == 0x684D); + + OK(uc_close(uc)); +} + TEST_LIST = { {"test_mips_stop_at_branch", test_mips_stop_at_branch}, {"test_mips_stop_at_delay_slot", test_mips_stop_at_delay_slot}, {"test_mips_el_ori", test_mips_el_ori}, {"test_mips_eb_ori", test_mips_eb_ori}, {"test_mips_lwx_exception_issue_1314", test_mips_lwx_exception_issue_1314}, + {"test_mips_mips16", test_mips_mips16}, {NULL, NULL}}; \ No newline at end of file