[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [Bug 670883] Re: ARM : ldrexd and strexd implementation fla
From: |
Peter Maydell |
Subject: |
[Qemu-devel] [Bug 670883] Re: ARM : ldrexd and strexd implementation flawed |
Date: |
Mon, 20 Dec 2010 13:23:58 -0000 |
The patch has now been merged into qemu's master git repo:
http://git.qemu.org/qemu.git/commit/?id=2c9adbda721c9996ec6b371cac4a00c1164b818e
(and so this bug should be fixed in the 0.14 release since that has not
yet branched.)
** Changed in: qemu
Status: New => Fix Committed
--
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 Committed
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).
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Qemu-devel] [Bug 670883] Re: ARM : ldrexd and strexd implementation flawed,
Peter Maydell <=