Signed-off-by: Paolo Bonzini <pbonz...@redhat.com> --- target/i386/tcg/decode-new.c.inc | 41 ++++++++ target/i386/tcg/decode-old.c.inc | 19 +--- target/i386/tcg/emit.c.inc | 166 ++++++++++++++++++++++++++++++- target/i386/tcg/translate.c | 17 ++++ 4 files changed, 227 insertions(+), 16 deletions(-)
diff --git a/target/i386/tcg/decode-new.c.inc b/target/i386/tcg/decode-new.c.inc index 3d96ac3adb..1e607b68fa 100644 --- a/target/i386/tcg/decode-new.c.inc +++ b/target/i386/tcg/decode-new.c.inc @@ -97,6 +97,9 @@ typedef enum X86OpSpecial { /* Writeback not needed or done manually in the callback */ X86_SPECIAL_NoWriteback, + /* Do not apply segment base to effective address */ + X86_SPECIAL_NoSeg, + /* Illegal or exclusive to 64-bit mode */ X86_SPECIAL_i64, X86_SPECIAL_o64, @@ -194,8 +197,12 @@ struct X86DecodedInsn { #define i64 .special = X86_SPECIAL_i64, #define o64 .special = X86_SPECIAL_o64, #define nowb .special = X86_SPECIAL_NoWriteback, +#define noseg .special = X86_SPECIAL_NoSeg, #define xchg .special = X86_SPECIAL_Locked, +static X86OpEntry illegal_opcode = + X86_OP_ENTRY0(illegal); + static uint8_t get_modrm(DisasContext *s, CPUX86State *env) { if (!s->has_modrm) { @@ -490,6 +497,18 @@ static void decode_group_1(DisasContext *s, CPUX86State *env, X86OpEntry *entry, } } +static void decode_group_1A(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b) +{ + int op = (get_modrm(s, env) >> 3) & 7; + if (op != 0) { + *entry = illegal_opcode; + } else { + entry->gen = gen_POP; + /* The address must use the value of ESP after the pop. */ + s->popl_esp_hack = 1 << mo_pushpop(s, s->dflag); + } +} + static X86OpEntry A2_00_F7[16][8] = { { X86_OP_ENTRY2(ADD, E,b, G,b), @@ -703,8 +722,24 @@ static X86OpEntry A2_08_FF[16][8] = { X86_OP_ENTRYr(Jcc, J,b), }, { + X86_OP_ENTRY3(MOV, E,b, G,b, None, None), + X86_OP_ENTRY3(MOV, E,v, G,v, None, None), + X86_OP_ENTRY3(MOV, G,b, E,b, None, None), + X86_OP_ENTRY3(MOV, G,v, E,v, None, None), + X86_OP_ENTRY3(MOV, E,v, S,w, None, None), + X86_OP_ENTRY3(LEA, G,v, M,v, None, None, noseg), + X86_OP_ENTRY3(MOV, S,w, E,v, None, None), + X86_OP_GROUPw(1A, E,v) }, { + X86_OP_ENTRY1(CBW, 0,v), /* rAX */ + X86_OP_ENTRY3(CWD, 2,v, 0,v, None, None), /* rDX, rAX */ + X86_OP_ENTRYr(CALLF, A,p, i64), + X86_OP_ENTRY0(WAIT), + X86_OP_ENTRY0(PUSHF), + X86_OP_ENTRY0(POPF), + X86_OP_ENTRY0(SAHF), + X86_OP_ENTRY0(LAHF), }, { }, @@ -982,6 +1017,7 @@ static target_ulong disas_insn_new(DisasContext *s, CPUState *cpu, int b) #if 0 s->pc_start = s->pc = s->base.pc_next; s->override = -1; + s->popl_esp_hack = 0; #ifdef TARGET_X86_64 s->rex_w = false; s->rex_r = 0; @@ -1170,6 +1206,11 @@ static target_ulong disas_insn_new(DisasContext *s, CPUState *cpu, int b) case X86_SPECIAL_NoWriteback: decode.op[0].alu_op_type = X86_ALU_SKIP; break; + + case X86_SPECIAL_NoSeg: + decode.mem.def_seg = -1; + s->override = -1; + break; } if (decode.op[0].has_ea || decode.op[1].has_ea || decode.op[2].has_ea) { diff --git a/target/i386/tcg/decode-old.c.inc b/target/i386/tcg/decode-old.c.inc index 7763bef11d..69ce70d141 100644 --- a/target/i386/tcg/decode-old.c.inc +++ b/target/i386/tcg/decode-old.c.inc @@ -1792,6 +1792,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) s->pc_start = s->pc = pc_start; s->override = -1; + s->popl_esp_hack = 0; #ifdef TARGET_X86_64 s->rex_w = false; s->rex_r = 0; @@ -2380,20 +2381,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) gen_op_ld_v(s, ot, s->T1, s->A0); gen_add_A0_im(s, 1 << ot); gen_op_ld_v(s, MO_16, s->T0, s->A0); - do_lcall: - if (PE(s) && !VM86(s)) { - tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0); - gen_helper_lcall_protected(cpu_env, s->tmp2_i32, s->T1, - tcg_const_i32(dflag - 1), - tcg_const_tl(s->pc - s->cs_base)); - } else { - tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0); - gen_helper_lcall_real(cpu_env, s->tmp2_i32, s->T1, - tcg_const_i32(dflag - 1), - tcg_const_i32(s->pc - s->cs_base)); - } - tcg_gen_ld_tl(s->tmp4, cpu_env, offsetof(CPUX86State, eip)); - gen_jr(s, s->tmp4); + gen_far_call(s); break; case 4: /* jmp Ev */ if (dflag == MO_16) { @@ -3964,7 +3952,8 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) tcg_gen_movi_tl(s->T0, selector); tcg_gen_movi_tl(s->T1, offset); } - goto do_lcall; + gen_far_call(s); + break; case 0xe9: /* jmp im */ if (dflag != MO_16) { tval = (int32_t)insn_get(env, s, MO_32); diff --git a/target/i386/tcg/emit.c.inc b/target/i386/tcg/emit.c.inc index 9395474302..22f2fbde79 100644 --- a/target/i386/tcg/emit.c.inc +++ b/target/i386/tcg/emit.c.inc @@ -227,6 +227,42 @@ static void gen_BOUND(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) } } +static void gen_CALLF(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + MemOp ot = decode->op[1].ot; + unsigned int selector, offset; + + if (CODE64(s)) { + gen_illegal_opcode(s); + return; + } + + offset = insn_get(env, s, ot); + selector = insn_get(env, s, MO_16); + tcg_gen_movi_tl(s->T0, selector); + tcg_gen_movi_tl(s->T1, offset); + return gen_far_call(s); +} + +static void gen_CBW(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + switch(decode->op[0].ot) { +#ifdef TARGET_X86_64 + case MO_64: + tcg_gen_ext32s_tl(s->T0, s->T0); + break; +#endif + case MO_32: + tcg_gen_ext16s_tl(s->T0, s->T0); + break; + case MO_16: + tcg_gen_ext8s_tl(s->T0, s->T0); + break; + default: + tcg_abort(); + } +} + static void gen_CMPS(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) { MemOp ot = decode->op[0].ot; @@ -239,6 +275,24 @@ static void gen_CMPS(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) } } +static void gen_CWD(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + int shift = 8 << decode->op[0].ot; + switch (shift) { + case 64: + break; + case 32: + tcg_gen_ext32s_tl(s->T0, s->T0); + break; + case 16: + tcg_gen_ext16s_tl(s->T0, s->T0); + break; + default: + tcg_abort(); + } + tcg_gen_sari_tl(s->T0, s->T0, shift - 1); +} + static void gen_DAA(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) { gen_update_cc_op(s); @@ -333,6 +387,22 @@ static void gen_Jcc(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) gen_jcc(s, decode->b & 0xf, decode->immediate, next_eip); } +static void gen_LAHF(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + if (CODE64(s) && !(s->cpuid_ext3_features & CPUID_EXT3_LAHF_LM)) { + return gen_illegal_opcode(s); + } + gen_compute_eflags(s); + /* Note: gen_compute_eflags() only gives the condition codes */ + tcg_gen_ori_tl(s->T0, cpu_cc_src, 0x02); + gen_op_mov_reg_v(s, MO_8, R_AH, s->T0); +} + +static void gen_LEA(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + tcg_gen_mov_tl(s->T0, s->A0); +} + static void gen_MOV(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) { /* nothing to do! */ @@ -392,10 +462,25 @@ static void gen_PUSHA(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) gen_pusha(s); } +static void gen_PUSHF(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + gen_svm_check_intercept(s, SVM_EXIT_PUSHF); + if (check_vm86_iopl(s)) { + gen_update_cc_op(s); + gen_helper_read_eflags(s->T0, cpu_env); + gen_push_v(s, s->T0); + } +} + static void gen_POP(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) { MemOp ot = gen_pop_T0(s); - /* NOTE: order is important for pop %sp */ + if (decode->op[0].alu_op_type == X86_ALU_MEM) { + /* NOTE: order is important for MMU exceptions */ + gen_op_st_v(s, ot, s->T0, s->A0); + decode->op[0].alu_op_type = X86_ALU_SKIP; + } + /* NOTE: writing back registers after update is important for pop %sp */ gen_pop_update(s, ot); } @@ -404,6 +489,76 @@ static void gen_POPA(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) gen_popa(s); } +static void gen_POPF(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + gen_svm_check_intercept(s, SVM_EXIT_POPF); + if (check_vm86_iopl(s)) { + MemOp ot = gen_pop_T0(s); + if (CPL(s) == 0) { + if (s->dflag != MO_16) { + gen_helper_write_eflags(cpu_env, s->T0, + tcg_const_i32((TF_MASK | AC_MASK | + ID_MASK | NT_MASK | + IF_MASK | + IOPL_MASK))); + } else { + gen_helper_write_eflags(cpu_env, s->T0, + tcg_const_i32((TF_MASK | AC_MASK | + ID_MASK | NT_MASK | + IF_MASK | IOPL_MASK) + & 0xffff)); + } + } else { + if (CPL(s) <= IOPL(s)) { + if (s->dflag != MO_16) { + gen_helper_write_eflags(cpu_env, s->T0, + tcg_const_i32((TF_MASK | + AC_MASK | + ID_MASK | + NT_MASK | + IF_MASK))); + } else { + gen_helper_write_eflags(cpu_env, s->T0, + tcg_const_i32((TF_MASK | + AC_MASK | + ID_MASK | + NT_MASK | + IF_MASK) + & 0xffff)); + } + } else { + if (s->dflag != MO_16) { + gen_helper_write_eflags(cpu_env, s->T0, + tcg_const_i32((TF_MASK | AC_MASK | + ID_MASK | NT_MASK))); + } else { + gen_helper_write_eflags(cpu_env, s->T0, + tcg_const_i32((TF_MASK | AC_MASK | + ID_MASK | NT_MASK) + & 0xffff)); + } + } + } + gen_pop_update(s, ot); + set_cc_op(s, CC_OP_EFLAGS); + /* abort translation because TF/AC flag may change */ + gen_jmp_im(s, s->pc - s->cs_base); + gen_eob(s); + } +} + +static void gen_SAHF(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + if (CODE64(s) && !(s->cpuid_ext3_features & CPUID_EXT3_LAHF_LM)) { + return gen_illegal_opcode(s); + } + gen_op_mov_v_reg(s, MO_8, s->T0, R_AH); + gen_compute_eflags(s); + tcg_gen_andi_tl(cpu_cc_src, cpu_cc_src, CC_O); + tcg_gen_andi_tl(s->T0, s->T0, CC_S | CC_Z | CC_A | CC_P | CC_C); + tcg_gen_or_tl(cpu_cc_src, cpu_cc_src, s->T0); +} + static void gen_SBB(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) { gen_alu_op(s, OP_SBBL, decode->op[0].ot); @@ -414,6 +569,15 @@ static void gen_SUB(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) gen_alu_op(s, OP_SUBL, decode->op[0].ot); } +static void gen_WAIT(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) +{ + if ((s->flags & (HF_MP_MASK | HF_TS_MASK)) == (HF_MP_MASK | HF_TS_MASK)) { + gen_exception(s, EXCP07_PREX, s->pc_start - s->cs_base); + } else { + gen_helper_fwait(cpu_env); + } +} + static void gen_XCHG(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode) { if (decode->b == 0x90 && !REX_B(s)) { diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index 5c3742a9c7..b742e456b0 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -2471,6 +2471,23 @@ static void gen_movl_seg_T0(DisasContext *s, X86Seg seg_reg) } } +static void gen_far_call(DisasContext *s) +{ + if (PE(s) && !VM86(s)) { + tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0); + gen_helper_lcall_protected(cpu_env, s->tmp2_i32, s->T1, + tcg_const_i32(s->dflag - 1), + tcg_const_tl(s->pc - s->cs_base)); + } else { + tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0); + gen_helper_lcall_real(cpu_env, s->tmp2_i32, s->T1, + tcg_const_i32(s->dflag - 1), + tcg_const_i32(s->pc - s->cs_base)); + } + tcg_gen_ld_tl(s->tmp4, cpu_env, offsetof(CPUX86State, eip)); + gen_jr(s, s->tmp4); +} + static void gen_svm_check_intercept(DisasContext *s, uint32_t type) { /* no SVM activated; fast case */ -- 2.37.1