From 7c7b0fe746b3815ba1d13e38f0b198b032f5611f Mon Sep 17 00:00:00 2001 From: "Emilio G. Cota" Date: Tue, 27 Feb 2018 22:49:18 -0500 Subject: [PATCH] target-i386: emulate LOCK'ed OP instructions using atomic helpers Backports commit a7cee522f3529c2fc85379237b391ea98823271e from qemu --- qemu/target-i386/translate.c | 78 +++++++++++++++++++++++++++--------- 1 file changed, 58 insertions(+), 20 deletions(-) diff --git a/qemu/target-i386/translate.c b/qemu/target-i386/translate.c index 5844a1f2..bbcec90b 100644 --- a/qemu/target-i386/translate.c +++ b/qemu/target-i386/translate.c @@ -1454,55 +1454,93 @@ static void gen_op(DisasContext *s, int op, TCGMemOp ot, int d) if (d != OR_TMP0) { gen_op_mov_v_reg(tcg_ctx, ot, cpu_T0, d); - } else { + } else if (!(s->prefix & PREFIX_LOCK)) { gen_op_ld_v(s, ot, cpu_T0, cpu_A0); } switch(op) { case OP_ADCL: - gen_compute_eflags_c(s, cpu_tmp4); - tcg_gen_add_tl(tcg_ctx, cpu_T0, cpu_T0, cpu_T1); - tcg_gen_add_tl(tcg_ctx, cpu_T0, cpu_T0, cpu_tmp4); - gen_op_st_rm_T0_A0(s, ot, d); + if (s->prefix & PREFIX_LOCK) { + tcg_gen_add_tl(tcg_ctx, cpu_T0, cpu_tmp4, cpu_T1); + tcg_gen_atomic_add_fetch_tl(tcg_ctx, cpu_T0, cpu_A0, cpu_T0, + s->mem_index, ot | MO_LE); + } else { + tcg_gen_add_tl(tcg_ctx, cpu_T0, cpu_T0, cpu_T1); + tcg_gen_add_tl(tcg_ctx, cpu_T0, cpu_T0, cpu_tmp4); + gen_op_st_rm_T0_A0(s, ot, d); + } gen_op_update3_cc(tcg_ctx, cpu_tmp4); set_cc_op(s, CC_OP_ADCB + ot); break; case OP_SBBL: - gen_compute_eflags_c(s, cpu_tmp4); - tcg_gen_sub_tl(tcg_ctx, cpu_T0, cpu_T0, cpu_T1); - tcg_gen_sub_tl(tcg_ctx, cpu_T0, cpu_T0, cpu_tmp4); - gen_op_st_rm_T0_A0(s, ot, d); + if (s->prefix & PREFIX_LOCK) { + tcg_gen_add_tl(tcg_ctx, cpu_T0, cpu_T1, cpu_tmp4); + tcg_gen_neg_tl(tcg_ctx, cpu_T0, cpu_T0); + tcg_gen_atomic_add_fetch_tl(tcg_ctx, cpu_T0, cpu_A0, cpu_T0, + s->mem_index, ot | MO_LE); + } else { + tcg_gen_sub_tl(tcg_ctx, cpu_T0, cpu_T0, cpu_T1); + tcg_gen_sub_tl(tcg_ctx, cpu_T0, cpu_T0, cpu_tmp4); + gen_op_st_rm_T0_A0(s, ot, d); + } gen_op_update3_cc(tcg_ctx, cpu_tmp4); set_cc_op(s, CC_OP_SBBB + ot); break; case OP_ADDL: - tcg_gen_add_tl(tcg_ctx, cpu_T0, cpu_T0, cpu_T1); - gen_op_st_rm_T0_A0(s, ot, d); + if (s->prefix & PREFIX_LOCK) { + tcg_gen_atomic_add_fetch_tl(tcg_ctx, cpu_T0, cpu_A0, cpu_T1, + s->mem_index, ot | MO_LE); + } else { + tcg_gen_add_tl(tcg_ctx, cpu_T0, cpu_T0, cpu_T1); + gen_op_st_rm_T0_A0(s, ot, d); + } gen_op_update2_cc(tcg_ctx); set_cc_op(s, CC_OP_ADDB + ot); break; case OP_SUBL: - tcg_gen_mov_tl(tcg_ctx, cpu_cc_srcT, cpu_T0); - tcg_gen_sub_tl(tcg_ctx, cpu_T0, cpu_T0, cpu_T1); - gen_op_st_rm_T0_A0(s, ot, d); + if (s->prefix & PREFIX_LOCK) { + tcg_gen_neg_tl(tcg_ctx, cpu_T0, cpu_T1); + tcg_gen_atomic_fetch_add_tl(tcg_ctx, cpu_cc_srcT, cpu_A0, cpu_T0, + s->mem_index, ot | MO_LE); + tcg_gen_sub_tl(tcg_ctx, cpu_T0, cpu_cc_srcT, cpu_T1); + } else { + tcg_gen_mov_tl(tcg_ctx, cpu_cc_srcT, cpu_T0); + tcg_gen_sub_tl(tcg_ctx, cpu_T0, cpu_T0, cpu_T1); + gen_op_st_rm_T0_A0(s, ot, d); + } gen_op_update2_cc(tcg_ctx); set_cc_op(s, CC_OP_SUBB + ot); break; default: case OP_ANDL: - tcg_gen_and_tl(tcg_ctx, cpu_T0, cpu_T0, cpu_T1); - gen_op_st_rm_T0_A0(s, ot, d); + if (s->prefix & PREFIX_LOCK) { + tcg_gen_atomic_and_fetch_tl(tcg_ctx, cpu_T0, cpu_A0, cpu_T1, + s->mem_index, ot | MO_LE); + } else { + tcg_gen_and_tl(tcg_ctx, cpu_T0, cpu_T0, cpu_T1); + gen_op_st_rm_T0_A0(s, ot, d); + } gen_op_update1_cc(tcg_ctx); set_cc_op(s, CC_OP_LOGICB + ot); break; case OP_ORL: - tcg_gen_or_tl(tcg_ctx, cpu_T0, cpu_T0, cpu_T1); - gen_op_st_rm_T0_A0(s, ot, d); + if (s->prefix & PREFIX_LOCK) { + tcg_gen_atomic_or_fetch_tl(tcg_ctx, cpu_T0, cpu_A0, cpu_T1, + s->mem_index, ot | MO_LE); + } else { + tcg_gen_or_tl(tcg_ctx, cpu_T0, cpu_T0, cpu_T1); + gen_op_st_rm_T0_A0(s, ot, d); + } gen_op_update1_cc(tcg_ctx); set_cc_op(s, CC_OP_LOGICB + ot); break; case OP_XORL: - tcg_gen_xor_tl(tcg_ctx, cpu_T0, cpu_T0, cpu_T1); - gen_op_st_rm_T0_A0(s, ot, d); + if (s->prefix & PREFIX_LOCK) { + tcg_gen_atomic_xor_fetch_tl(tcg_ctx, cpu_T0, cpu_A0, cpu_T1, + s->mem_index, ot | MO_LE); + } else { + tcg_gen_xor_tl(tcg_ctx, cpu_T0, cpu_T0, cpu_T1); + gen_op_st_rm_T0_A0(s, ot, d); + } gen_op_update1_cc(tcg_ctx); set_cc_op(s, CC_OP_LOGICB + ot); break;