target/arm: Don't skip M-profile reset entirely in user mode
Currently all of the M-profile specific code in arm_cpu_reset() is inside a !defined(CONFIG_USER_ONLY) ifdef block. This is unintentional: it happened because originally the only M-profile-specific handling was the setup of the initial SP and PC from the vector table, which is system-emulation only. But then we added a lot of other M-profile setup to the same "if (ARM_FEATURE_M)" code block without noticing that it was all inside a not-user-mode ifdef. This has generally been harmless, but with the addition of v8.1M low-overhead-loop support we ran into a problem: the reset of FPSCR.LTPSIZE to 4 was only being done for system emulation mode, so if a user-mode guest tried to execute the LE instruction it would incorrectly take a UsageFault. Adjust the ifdefs so only the really system-emulation specific parts are covered. Because this means we now run some reset code that sets up initial values in the FPCCR and similar FPU related registers, explicitly set up the registers controlling FPU context handling in user-emulation mode so that the FPU works by design and not by chance. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/613 Cc: qemu-stable@nongnu.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20210914120725.24992-2-peter.maydell@linaro.org
This commit is contained in:
parent
f015cbb546
commit
b62ceeaf80
@ -265,12 +265,15 @@ static void arm_cpu_reset(DeviceState *dev)
|
||||
env->uncached_cpsr = ARM_CPU_MODE_SVC;
|
||||
}
|
||||
env->daif = PSTATE_D | PSTATE_A | PSTATE_I | PSTATE_F;
|
||||
#endif
|
||||
|
||||
if (arm_feature(env, ARM_FEATURE_M)) {
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
uint32_t initial_msp; /* Loaded from 0x0 */
|
||||
uint32_t initial_pc; /* Loaded from 0x4 */
|
||||
uint8_t *rom;
|
||||
uint32_t vecbase;
|
||||
#endif
|
||||
|
||||
if (cpu_isar_feature(aa32_lob, cpu)) {
|
||||
/*
|
||||
@ -324,6 +327,8 @@ static void arm_cpu_reset(DeviceState *dev)
|
||||
env->v7m.fpccr[M_REG_S] = R_V7M_FPCCR_ASPEN_MASK |
|
||||
R_V7M_FPCCR_LSPEN_MASK | R_V7M_FPCCR_S_MASK;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
/* Unlike A/R profile, M profile defines the reset LR value */
|
||||
env->regs[14] = 0xffffffff;
|
||||
|
||||
@ -352,8 +357,22 @@ static void arm_cpu_reset(DeviceState *dev)
|
||||
env->regs[13] = initial_msp & 0xFFFFFFFC;
|
||||
env->regs[15] = initial_pc & ~1;
|
||||
env->thumb = initial_pc & 1;
|
||||
#else
|
||||
/*
|
||||
* For user mode we run non-secure and with access to the FPU.
|
||||
* The FPU context is active (ie does not need further setup)
|
||||
* and is owned by non-secure.
|
||||
*/
|
||||
env->v7m.secure = false;
|
||||
env->v7m.nsacr = 0xcff;
|
||||
env->v7m.cpacr[M_REG_NS] = 0xf0ffff;
|
||||
env->v7m.fpccr[M_REG_S] &=
|
||||
~(R_V7M_FPCCR_LSPEN_MASK | R_V7M_FPCCR_S_MASK);
|
||||
env->v7m.control[M_REG_S] |= R_V7M_CONTROL_FPCA_MASK;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
/* AArch32 has a hard highvec setting of 0xFFFF0000. If we are currently
|
||||
* executing as AArch32 then check if highvecs are enabled and
|
||||
* adjust the PC accordingly.
|
||||
|
Loading…
Reference in New Issue
Block a user