From abf80f880410ebbdd01a289c41c87153802fe900 Mon Sep 17 00:00:00 2001 From: Andreas Gustafsson Date: Mon, 12 Dec 2011 00:46:32 +0400 Subject: [PATCH 10/25] target-i386: fix cmpxchg instruction emulation When the i386 cmpxchg instruction is executed with a memory operand and the comparison result is "unequal", do the memory write before changing the accumulator instead of the other way around, because otherwise the new accumulator value will incorrectly be used in the comparison when the instruction is restarted after a page fault. This bug was originally reported on 2010-04-25 as https://bugs.launchpad.net/qemu/+bug/569760 Signed-off-by: Andreas Gustafsson --- target-i386/translate.c | 11 +++++++---- 1 files changed, 7 insertions(+), 4 deletions(-) diff --git a/target-i386/translate.c b/target-i386/translate.c index 1ef8d16..8321bf3 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -4870,20 +4870,23 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) tcg_gen_sub_tl(t2, cpu_regs[R_EAX], t0); gen_extu(ot, t2); tcg_gen_brcondi_tl(TCG_COND_EQ, t2, 0, label1); + label2 = gen_new_label(); if (mod == 3) { - label2 = gen_new_label(); gen_op_mov_reg_v(ot, R_EAX, t0); tcg_gen_br(label2); gen_set_label(label1); gen_op_mov_reg_v(ot, rm, t1); - gen_set_label(label2); } else { - tcg_gen_mov_tl(t1, t0); + /* perform no-op store cycle like physical cpu; must be + before changing accumulator to ensure idempotency if + the store faults and the instruction is restarted */ + gen_op_st_v(ot + s->mem_index, t0, a0); gen_op_mov_reg_v(ot, R_EAX, t0); + tcg_gen_br(label2); gen_set_label(label1); - /* always store */ gen_op_st_v(ot + s->mem_index, t1, a0); } + gen_set_label(label2); tcg_gen_mov_tl(cpu_cc_src, t0); tcg_gen_mov_tl(cpu_cc_dst, t2); s->cc_op = CC_OP_SUBB + ot; -- 1.7.7.5