qemu-devel
[Top][All Lists]
Advanced

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

[Qemu-devel] [Bug 670883] Re: ARM : ldrexd and strexd implementation fla


From: Aurelien Jarno
Subject: [Qemu-devel] [Bug 670883] Re: ARM : ldrexd and strexd implementation flawed
Date: Sun, 20 Feb 2011 17:17:15 -0000

** Changed in: qemu
       Status: Fix Committed => Fix Released

-- 
You received this bug notification because you are a member of qemu-
devel-ml, which is subscribed to QEMU.
https://bugs.launchpad.net/bugs/670883

Title:
  ARM : ldrexd and strexd implementation flawed

Status in QEMU:
  Fix Released

Bug description:
  The ldrexd / strexd instructions have a flawed implementation : it
  never works properly.  For example, the most simple code something
  like:

  ldrexd r0, r1, [r2]
  strexd r4, r0, r1, [r2]

  which should usually have r4 as zero (successfully done the exclusive
  store).  However, the current implementation always returns one
  (unsuccessfully done the exclusive store).

  The current trunk (function gen_load_exclusive, gen_store_exclusive,
  both from target-arm/translate.c) looks like an incorrect
  implementation:

  static void gen_load_exclusive(DisasContext *s, int rt, int rt2,
                                 TCGv addr, int size)
  {
      TCGv tmp;

      switch (size) {
      case 0:
          tmp = gen_ld8u(addr, IS_USER(s));
          break;
      case 1:
          tmp = gen_ld16u(addr, IS_USER(s));
          break;
      case 2:
      case 3:
          tmp = gen_ld32(addr, IS_USER(s));
          break;
      default:
          abort();
      }
      tcg_gen_mov_i32(cpu_exclusive_val, tmp);
      store_reg(s, rt, tmp);
      if (size == 3) {
          tcg_gen_addi_i32(addr, addr, 4);
          tmp = gen_ld32(addr, IS_USER(s));
          tcg_gen_mov_i32(cpu_exclusive_high, tmp);
          store_reg(s, rt2, tmp);
      }
      tcg_gen_mov_i32(cpu_exclusive_addr, addr);
  }

  The problem lies when size is 3 (=ldrexd) : normally,
  cpu_exclusive_addr should be set as addr, but since the current
  implementation increments addr by 4 (when size is 3) before
  cpu_exclusive_addr is updated, it results in a wrong value stored on
  cpu_exclusive_addr.

  Another error on gen_store_exclusive():

  ...
      if (size == 3) {
          TCGv tmp2 = new_tmp();
          tcg_gen_addi_i32(tmp2, addr, 4);
          tmp = gen_ld32(addr, IS_USER(s));
          dead_tmp(tmp2);
          tcg_gen_brcond_i32(TCG_COND_NE, tmp, cpu_exclusive_high, fail_label);
          dead_tmp(tmp);
      }
  ....

  the current code assigns tmp2 as addr + 4, but loads from addr on the
  next line, not from tmp2(=addr+4).



reply via email to

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