aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2016-02-23 15:36:44 +0000
committerPeter Maydell <peter.maydell@linaro.org>2016-02-26 15:09:41 +0000
commit81907a582901671c15be36a63b5063f88f3487e2 (patch)
treeaedfb83c41058e9e02c32d99ffe6c388207ebeb2
parent58ae2d1f037fae1d90eed4522053a85d79edfbec (diff)
target-arm: In v8, make illegal AArch32 mode changes set PSTATE.IL
In v8, the illegal mode changes which are UNPREDICTABLE in v7 are given architected behaviour: * the mode field is unchanged * PSTATE.IL is set (so any subsequent instructions will UNDEF) * any other CPSR fields are written to as normal This is pretty much the same behaviour we picked for our UNPREDICTABLE handling, with the exception that for v8 we need to set the IL bit. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Sergey Fedorov <serge.fdrv@gmail.com> Message-id: 1455556977-3644-10-git-send-email-peter.maydell@linaro.org
-rw-r--r--target-arm/helper.c15
1 files changed, 12 insertions, 3 deletions
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 5926b15506..ff5f8955a1 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -5325,11 +5325,20 @@ void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask,
(env->uncached_cpsr & CPSR_M) != CPSR_USER &&
((env->uncached_cpsr ^ val) & mask & CPSR_M)) {
if (bad_mode_switch(env, val & CPSR_M)) {
- /* Attempt to switch to an invalid mode: this is UNPREDICTABLE.
- * We choose to ignore the attempt and leave the CPSR M field
- * untouched.
+ /* Attempt to switch to an invalid mode: this is UNPREDICTABLE in
+ * v7, and has defined behaviour in v8:
+ * + leave CPSR.M untouched
+ * + allow changes to the other CPSR fields
+ * + set PSTATE.IL
+ * For user changes via the GDB stub, we don't set PSTATE.IL,
+ * as this would be unnecessarily harsh for a user error.
*/
mask &= ~CPSR_M;
+ if (write_type != CPSRWriteByGDBStub &&
+ arm_feature(env, ARM_FEATURE_V8)) {
+ mask |= CPSR_IL;
+ val |= CPSR_IL;
+ }
} else {
switch_mode(env, val & CPSR_M);
}