qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH] target-arm: Fix handling of STM (user) with r15


From: Greg Bellows
Subject: Re: [Qemu-devel] [PATCH] target-arm: Fix handling of STM (user) with r15 in register list
Date: Tue, 17 Mar 2015 10:24:23 -0700

On Tue, Mar 10, 2015 at 12:18 PM, Peter Maydell
<address@hidden> wrote:
> The A32 encoding of LDM distinguishes LDM (user) from LDM (exception
> return) based on whether r15 is in the register list. However for
> STM (user) there is no equivalent distinction. We were incorrectly
> treating "r15 in list" as indicating exception return for both LDM
> and STM, with the result that an STM (user) involving r15 went into
> an infinite loop. Fix this; note that the value stored for r15
> in this case is the current PC regardless of our current mode.
>
> Signed-off-by: Peter Maydell <address@hidden>
> ---
>  target-arm/translate.c | 18 ++++++++++++------
>  1 file changed, 12 insertions(+), 6 deletions(-)
>
> diff --git a/target-arm/translate.c b/target-arm/translate.c
> index 36868ed..ed8fcea 100644
> --- a/target-arm/translate.c
> +++ b/target-arm/translate.c
> @@ -8859,17 +8859,23 @@ static void disas_arm_insn(DisasContext *s, unsigned 
> int insn)
>          case 0x08:
>          case 0x09:
>              {
> -                int j, n, user, loaded_base;
> +                int j, n, loaded_base;
> +                bool exc_return = false;
> +                bool is_load = extract32(insn, 20, 1);
> +                bool user = false;
>                  TCGv_i32 loaded_var;
>                  /* load/store multiple words */
>                  /* XXX: store correct base if write back */
> -                user = 0;
>                  if (insn & (1 << 22)) {
> +                    /* LDM (user), LDM (exception return) and STM (user) */
>                      if (IS_USER(s))
>                          goto illegal_op; /* only usable in supervisor mode */
>
> -                    if ((insn & (1 << 15)) == 0)
> -                        user = 1;
> +                    if (is_load && extract32(insn, 15, 1)) {
> +                        exc_return = true;
> +                    } else {
> +                        user = true;
> +                    }
>                  }
>                  rn = (insn >> 16) & 0xf;
>                  addr = load_reg(s, rn);
> @@ -8903,7 +8909,7 @@ static void disas_arm_insn(DisasContext *s, unsigned 
> int insn)
>                  j = 0;
>                  for(i=0;i<16;i++) {
>                      if (insn & (1 << i)) {
> -                        if (insn & (1 << 20)) {
> +                        if (is_load) {
>                              /* load */
>                              tmp = tcg_temp_new_i32();
>                              gen_aa32_ld32u(tmp, addr, get_mem_index(s));
> @@ -8968,7 +8974,7 @@ static void disas_arm_insn(DisasContext *s, unsigned 
> int insn)
>                  if (loaded_base) {
>                      store_reg(s, rn, loaded_var);
>                  }
> -                if ((insn & (1 << 22)) && !user) {
> +                if (exc_return) {
>                      /* Restore CPSR from SPSR.  */
>                      tmp = load_cpu_field(spsr);
>                      gen_set_cpsr(tmp, CPSR_ERET_MASK);
> --
> 1.9.1
>
>

Reviewed-by: Greg Bellows <address@hidden>



reply via email to

[Prev in Thread] Current Thread [Next in Thread]