From 47097b55b79492c75f27ffb85f93aea2a3191dd7 Mon Sep 17 00:00:00 2001 From: lazymio Date: Tue, 4 Jan 2022 21:01:20 +0100 Subject: [PATCH] Fix #1520 --- qemu/target/arm/cpu.h | 1 + qemu/target/arm/helper.c | 9 ++++++--- qemu/target/arm/unicorn_arm.c | 6 +++--- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/qemu/target/arm/cpu.h b/qemu/target/arm/cpu.h index 2e734a62..3ddb1da6 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 48c9b013..0ee137f9 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 95bd93b5..f98a61bb 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;