diff --git a/qemu/target/arm/cpu.h b/qemu/target/arm/cpu.h index 2e734a6218..3ddb1da691 100644 --- a/qemu/target/arm/cpu.h +++ b/qemu/target/arm/cpu.h @@ -1264,6 +1264,7 @@ typedef enum CPSRWriteType { CPSRWriteExceptionReturn = 1, /* from guest exception return insn */ CPSRWriteRaw = 2, /* trust values, do not switch reg banks */ CPSRWriteByGDBStub = 3, /* from the GDB stub */ + CPSRWriteByUnicorn = 4 /* from uc_reg_write */ } CPSRWriteType; /* Set the CPSR. Note that some bits of mask must be all-set or all-clear.*/ diff --git a/qemu/target/arm/helper.c b/qemu/target/arm/helper.c index 48c9b013f1..0ee137f928 100644 --- a/qemu/target/arm/helper.c +++ b/qemu/target/arm/helper.c @@ -7983,9 +7983,12 @@ void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask, * to switch mode. (Those are caught by translate.c for writes * triggered by guest instructions.) */ - // mask &= ~CPSR_M; - // Unicorn: No, it can also be uc_reg_write - switch_mode(env, val & CPSR_M); + mask &= ~CPSR_M; + + // Unicorn: No, it can also be uc_reg_write, let user switch registers banks. + if (write_type == CPSRWriteByUnicorn) { + switch_mode(env, val & CPSR_M); + } } else if (bad_mode_switch(env, val & CPSR_M, write_type)) { /* Attempt to switch to an invalid mode: this is UNPREDICTABLE in * v7, and has defined behaviour in v8: diff --git a/qemu/target/arm/unicorn_arm.c b/qemu/target/arm/unicorn_arm.c index 95bd93b591..f98a61bb47 100644 --- a/qemu/target/arm/unicorn_arm.c +++ b/qemu/target/arm/unicorn_arm.c @@ -251,17 +251,17 @@ static void reg_write(CPUARMState *env, unsigned int regid, const void *value) case UC_ARM_REG_APSR: if (!arm_feature(env, ARM_FEATURE_M)) { cpsr_write(env, *(uint32_t *)value, - (CPSR_NZCV | CPSR_Q | CPSR_GE), CPSRWriteByInstr); + (CPSR_NZCV | CPSR_Q | CPSR_GE), CPSRWriteByUnicorn); } else { // Same with UC_ARM_REG_APSR_NZCVQ v7m_msr_xpsr(env, 0b1000, 0, *(uint32_t *)value); } break; case UC_ARM_REG_APSR_NZCV: - cpsr_write(env, *(uint32_t *)value, CPSR_NZCV, CPSRWriteByInstr); + cpsr_write(env, *(uint32_t *)value, CPSR_NZCV, CPSRWriteByUnicorn); break; case UC_ARM_REG_CPSR: - cpsr_write(env, *(uint32_t *)value, ~0, CPSRWriteByInstr); + cpsr_write(env, *(uint32_t *)value, ~0, CPSRWriteByUnicorn); break; case UC_ARM_REG_SPSR: env->spsr = *(uint32_t *)value;