89 lines
3.5 KiB
Diff
89 lines
3.5 KiB
Diff
|
From: Peter Maydell <peter.maydell@linaro.org>
|
||
|
Date: Mon, 20 Sep 2021 09:54:33 +0100
|
||
|
Subject: target/arm: Don't skip M-profile reset entirely in user mode
|
||
|
|
||
|
Git-commit: b62ceeaf8096fdbbbfdc6087da0028bc4a4dd77e
|
||
|
|
||
|
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
|
||
|
Signed-off-by: Li Zhang <li.zhang@suse.com>
|
||
|
---
|
||
|
target/arm/cpu.c | 19 +++++++++++++++++++
|
||
|
1 file changed, 19 insertions(+)
|
||
|
|
||
|
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
|
||
|
index 2866dd765882c87eb773493d04cd..af60c07ca1421558cae5cc2e3128 100644
|
||
|
--- a/target/arm/cpu.c
|
||
|
+++ b/target/arm/cpu.c
|
||
|
@@ -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.
|