target-arm: Correct handling of writes to CPSR mode bits from gdb in usermode
In helper.c the expression (env->uncached_cpsr & CPSR_M) != CPSR_USER is always true; the right hand side was supposed to be ARM_CPU_MODE_USR (an error in commitcb01d391
). Since the incorrect expression was always true, this just meant that commitcb01d391
had no effect. However simply changing the RHS here would reveal a logic error: if the mode is USR we wish to completely ignore the attempt to set the mode bits, which means that we must clear the CPSR_M bits from mask to avoid the uncached_cpsr bits being updated at the end of the function. Move the condition into the correct place in the code, fix its RHS constant, and add a comment about the fact that we must be doing a gdbstub write if we're in user mode. Fixes: https://bugs.launchpad.net/qemu/+bug/1550503 Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Sergey Fedorov <serge.fdrv@gmail.com> Message-id: 1456764438-30015-1-git-send-email-peter.maydell@linaro.org
This commit is contained in:
parent
2d3b7c0164
commit
8c4f0eb94c
|
@ -5490,9 +5490,16 @@ void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask,
|
||||||
env->daif |= val & CPSR_AIF & mask;
|
env->daif |= val & CPSR_AIF & mask;
|
||||||
|
|
||||||
if (write_type != CPSRWriteRaw &&
|
if (write_type != CPSRWriteRaw &&
|
||||||
(env->uncached_cpsr & CPSR_M) != CPSR_USER &&
|
|
||||||
((env->uncached_cpsr ^ val) & mask & CPSR_M)) {
|
((env->uncached_cpsr ^ val) & mask & CPSR_M)) {
|
||||||
if (bad_mode_switch(env, val & CPSR_M, write_type)) {
|
if ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR) {
|
||||||
|
/* Note that we can only get here in USR mode if this is a
|
||||||
|
* gdb stub write; for this case we follow the architectural
|
||||||
|
* behaviour for guest writes in USR mode of ignoring an attempt
|
||||||
|
* to switch mode. (Those are caught by translate.c for writes
|
||||||
|
* triggered by guest instructions.)
|
||||||
|
*/
|
||||||
|
mask &= ~CPSR_M;
|
||||||
|
} else if (bad_mode_switch(env, val & CPSR_M, write_type)) {
|
||||||
/* Attempt to switch to an invalid mode: this is UNPREDICTABLE in
|
/* Attempt to switch to an invalid mode: this is UNPREDICTABLE in
|
||||||
* v7, and has defined behaviour in v8:
|
* v7, and has defined behaviour in v8:
|
||||||
* + leave CPSR.M untouched
|
* + leave CPSR.M untouched
|
||||||
|
|
Loading…
Reference in New Issue