diff options
Diffstat (limited to 'target')
-rw-r--r-- | target/arm/cpu.c | 5 | ||||
-rw-r--r-- | target/arm/cpu.h | 4 | ||||
-rw-r--r-- | target/arm/helper.c | 18 | ||||
-rw-r--r-- | target/arm/machine.c | 33 |
4 files changed, 41 insertions, 19 deletions
diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 05c038bf17..b241a634cf 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -185,11 +185,6 @@ static void arm_cpu_reset(CPUState *s) uint32_t initial_pc; /* Loaded from 0x4 */ uint8_t *rom; - /* For M profile we store FAULTMASK and PRIMASK in the - * PSTATE F and I bits; these are both clear at reset. - */ - env->daif &= ~(PSTATE_I | PSTATE_F); - /* The reset value of this bit is IMPDEF, but ARM recommends * that it resets to 1, so QEMU always does that rather than making * it dependent on CPU model. diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 0b9f9377f8..8ef552a0a2 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -418,6 +418,8 @@ typedef struct CPUARMState { uint32_t bfar; /* BusFault Address */ unsigned mpu_ctrl; /* MPU_CTRL */ int exception; + uint32_t primask; + uint32_t faultmask; } v7m; /* Information associated with an exception about to be taken: @@ -2178,7 +2180,7 @@ static inline int cpu_mmu_index(CPUARMState *env, bool ifetch) * we're in a HardFault or NMI handler. */ if ((env->v7m.exception > 0 && env->v7m.exception <= 3) - || env->daif & PSTATE_F) { + || env->v7m.faultmask) { return arm_to_core_mmu_idx(ARMMMUIdx_MNegPri); } diff --git a/target/arm/helper.c b/target/arm/helper.c index 439ad86d49..941085690b 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -6167,7 +6167,7 @@ static void do_v7m_exception_exit(ARMCPU *cpu) if (env->v7m.exception != ARMV7M_EXCP_NMI) { /* Auto-clear FAULTMASK on return from other than NMI */ - env->daif &= ~PSTATE_F; + env->v7m.faultmask = 0; } switch (armv7m_nvic_complete_irq(env->nvic, env->v7m.exception)) { @@ -8713,12 +8713,12 @@ uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg) return (env->v7m.control & R_V7M_CONTROL_SPSEL_MASK) ? env->regs[13] : env->v7m.other_sp; case 16: /* PRIMASK */ - return (env->daif & PSTATE_I) != 0; + return env->v7m.primask; case 17: /* BASEPRI */ case 18: /* BASEPRI_MAX */ return env->v7m.basepri; case 19: /* FAULTMASK */ - return (env->daif & PSTATE_F) != 0; + return env->v7m.faultmask; default: qemu_log_mask(LOG_GUEST_ERROR, "Attempt to read unknown special" " register %d\n", reg); @@ -8773,11 +8773,7 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val) } break; case 16: /* PRIMASK */ - if (val & 1) { - env->daif |= PSTATE_I; - } else { - env->daif &= ~PSTATE_I; - } + env->v7m.primask = val & 1; break; case 17: /* BASEPRI */ env->v7m.basepri = val & 0xff; @@ -8788,11 +8784,7 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t maskreg, uint32_t val) env->v7m.basepri = val; break; case 19: /* FAULTMASK */ - if (val & 1) { - env->daif |= PSTATE_F; - } else { - env->daif &= ~PSTATE_F; - } + env->v7m.faultmask = val & 1; break; case 20: /* CONTROL */ /* Writing to the SPSEL bit only has an effect if we are in diff --git a/target/arm/machine.c b/target/arm/machine.c index 1f66da4a2c..2fb4b76296 100644 --- a/target/arm/machine.c +++ b/target/arm/machine.c @@ -97,6 +97,17 @@ static bool m_needed(void *opaque) return arm_feature(env, ARM_FEATURE_M); } +static const VMStateDescription vmstate_m_faultmask_primask = { + .name = "cpu/m/faultmask-primask", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(env.v7m.faultmask, ARMCPU), + VMSTATE_UINT32(env.v7m.primask, ARMCPU), + VMSTATE_END_OF_LIST() + } +}; + static const VMStateDescription vmstate_m = { .name = "cpu/m", .version_id = 4, @@ -115,6 +126,10 @@ static const VMStateDescription vmstate_m = { VMSTATE_UINT32(env.v7m.mpu_ctrl, ARMCPU), VMSTATE_INT32(env.v7m.exception, ARMCPU), VMSTATE_END_OF_LIST() + }, + .subsections = (const VMStateDescription*[]) { + &vmstate_m_faultmask_primask, + NULL } }; @@ -201,6 +216,24 @@ static int get_cpsr(QEMUFile *f, void *opaque, size_t size, CPUARMState *env = &cpu->env; uint32_t val = qemu_get_be32(f); + if (arm_feature(env, ARM_FEATURE_M)) { + /* If the I or F bits are set then this is a migration from + * an old QEMU which still stored the M profile FAULTMASK + * and PRIMASK in env->daif. Set v7m.faultmask and v7m.primask + * accordingly, and then clear the bits so they don't confuse + * cpsr_write(). For a new QEMU, the bits here will always be + * clear, and the data is transferred using the + * vmstate_m_faultmask_primask subsection. + */ + if (val & CPSR_F) { + env->v7m.faultmask = 1; + } + if (val & CPSR_I) { + env->v7m.primask = 1; + } + val &= ~(CPSR_F | CPSR_I); + } + env->aarch64 = ((val & PSTATE_nRW) == 0); if (is_a64(env)) { |