Message ID | 1456764438-30015-1-git-send-email-peter.maydell@linaro.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On 29.02.2016 19:47, Peter Maydell wrote: > 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 commit cb01d391). > > Since the incorrect expression was always true, this just meant that > commit cb01d391 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> > --- > target-arm/helper.c | 11 +++++++++-- > 1 file changed, 9 insertions(+), 2 deletions(-) > > diff --git a/target-arm/helper.c b/target-arm/helper.c > index 18c8296..935f13b 100644 > --- a/target-arm/helper.c > +++ b/target-arm/helper.c > @@ -5490,9 +5490,16 @@ void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask, > env->daif |= val & CPSR_AIF & mask; > > if (write_type != CPSRWriteRaw && > - (env->uncached_cpsr & CPSR_M) != CPSR_USER && > ((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 > * v7, and has defined behaviour in v8: > * + leave CPSR.M untouched
diff --git a/target-arm/helper.c b/target-arm/helper.c index 18c8296..935f13b 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -5490,9 +5490,16 @@ void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask, env->daif |= val & CPSR_AIF & mask; if (write_type != CPSRWriteRaw && - (env->uncached_cpsr & CPSR_M) != CPSR_USER && ((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 * v7, and has defined behaviour in v8: * + leave CPSR.M untouched
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 commit cb01d391). Since the incorrect expression was always true, this just meant that commit cb01d391 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> --- target-arm/helper.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)