X-Git-Url: http://git.maemo.org/git/?a=blobdiff_plain;f=qemu%2Ftarget-i386%2Ftranslate.c;h=f905f323dd6a34dc03f5286af6b8ac2578825488;hb=534292fea694c0ce3060be20fbd715d0d6bfe3f0;hp=c4584a01204126b4def12f366c91480b4f7854e1;hpb=4e314c6a1b983419a00d8146bc9234defbfe2e64;p=qemu diff --git a/qemu/target-i386/translate.c b/qemu/target-i386/translate.c index c4584a0..f905f32 100644 --- a/qemu/target-i386/translate.c +++ b/qemu/target-i386/translate.c @@ -100,6 +100,7 @@ typedef struct DisasContext { int popl_esp_hack; /* for correct popl with esp base handling */ int rip_offset; /* only used in x86_64, but left for simplicity */ int cpuid_features; + int cpuid_ext_features; } DisasContext; static void gen_eob(DisasContext *s); @@ -1627,7 +1628,14 @@ static void gen_add_A0_ds_seg(DisasContext *s) override = R_DS; } if (must_add_seg) { - gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base)); +#ifdef TARGET_X86_64 + if (CODE64(s)) { + gen_op_addq_A0_seg(offsetof(CPUX86State,segs[override].base)); + } else +#endif + { + gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base)); + } } } @@ -1693,6 +1701,31 @@ static inline int insn_const_size(unsigned int ot) return 4; } +static inline void gen_goto_tb(DisasContext *s, int tb_num, target_ulong eip) +{ + TranslationBlock *tb; + target_ulong pc; + + pc = s->cs_base + eip; + tb = s->tb; + /* NOTE: we handle the case where the TB spans two pages here */ + if ((pc & TARGET_PAGE_MASK) == (tb->pc & TARGET_PAGE_MASK) || + (pc & TARGET_PAGE_MASK) == ((s->pc - 1) & TARGET_PAGE_MASK)) { + /* jump to same page: we can use a direct jump */ + if (tb_num == 0) + gen_op_goto_tb0(TBPARAM(tb)); + else + gen_op_goto_tb1(TBPARAM(tb)); + gen_jmp_im(eip); + gen_op_movl_T0_im((long)tb + tb_num); + gen_op_exit_tb(); + } else { + /* jump to another page: currently not optimized */ + gen_jmp_im(eip); + gen_eob(s); + } +} + static inline void gen_jcc(DisasContext *s, int b, target_ulong val, target_ulong next_eip) { @@ -1772,8 +1805,10 @@ static inline void gen_jcc(DisasContext *s, int b, break; } - if (s->cc_op != CC_OP_DYNAMIC) + if (s->cc_op != CC_OP_DYNAMIC) { gen_op_set_cc_op(s->cc_op); + s->cc_op = CC_OP_DYNAMIC; + } if (!func) { gen_setcc_slow[jcc_op](); @@ -1790,16 +1825,10 @@ static inline void gen_jcc(DisasContext *s, int b, l1 = gen_new_label(); func(l1); - gen_op_goto_tb0(TBPARAM(tb)); - gen_jmp_im(next_eip); - gen_op_movl_T0_im((long)tb + 0); - gen_op_exit_tb(); + gen_goto_tb(s, 0, next_eip); gen_set_label(l1); - gen_op_goto_tb1(TBPARAM(tb)); - gen_jmp_im(val); - gen_op_movl_T0_im((long)tb + 1); - gen_op_exit_tb(); + gen_goto_tb(s, 1, val); s->is_jmp = 3; } else { @@ -1948,10 +1977,14 @@ static void gen_push_T0(DisasContext *s) { #ifdef TARGET_X86_64 if (CODE64(s)) { - /* XXX: check 16 bit behaviour */ gen_op_movq_A0_reg[R_ESP](); - gen_op_subq_A0_8(); - gen_op_st_T0_A0[OT_QUAD + s->mem_index](); + if (s->dflag) { + gen_op_subq_A0_8(); + gen_op_st_T0_A0[OT_QUAD + s->mem_index](); + } else { + gen_op_subq_A0_2(); + gen_op_st_T0_A0[OT_WORD + s->mem_index](); + } gen_op_movq_ESP_A0(); } else #endif @@ -1985,10 +2018,14 @@ static void gen_push_T1(DisasContext *s) { #ifdef TARGET_X86_64 if (CODE64(s)) { - /* XXX: check 16 bit behaviour */ gen_op_movq_A0_reg[R_ESP](); - gen_op_subq_A0_8(); - gen_op_st_T1_A0[OT_QUAD + s->mem_index](); + if (s->dflag) { + gen_op_subq_A0_8(); + gen_op_st_T1_A0[OT_QUAD + s->mem_index](); + } else { + gen_op_subq_A0_2(); + gen_op_st_T0_A0[OT_WORD + s->mem_index](); + } gen_op_movq_ESP_A0(); } else #endif @@ -2020,9 +2057,8 @@ static void gen_pop_T0(DisasContext *s) { #ifdef TARGET_X86_64 if (CODE64(s)) { - /* XXX: check 16 bit behaviour */ gen_op_movq_A0_reg[R_ESP](); - gen_op_ld_T0_A0[OT_QUAD + s->mem_index](); + gen_op_ld_T0_A0[(s->dflag ? OT_QUAD : OT_WORD) + s->mem_index](); } else #endif { @@ -2041,7 +2077,7 @@ static void gen_pop_T0(DisasContext *s) static void gen_pop_update(DisasContext *s) { #ifdef TARGET_X86_64 - if (CODE64(s)) { + if (CODE64(s) && s->dflag) { gen_stack_update(s, 8); } else #endif @@ -2105,26 +2141,48 @@ static void gen_enter(DisasContext *s, int esp_addend, int level) { int ot, opsize; - ot = s->dflag + OT_WORD; level &= 0x1f; - opsize = 2 << s->dflag; - - gen_op_movl_A0_ESP(); - gen_op_addl_A0_im(-opsize); - if (!s->ss32) - gen_op_andl_A0_ffff(); - gen_op_movl_T1_A0(); - if (s->addseg) - gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base)); - /* push bp */ - gen_op_mov_TN_reg[OT_LONG][0][R_EBP](); - gen_op_st_T0_A0[ot + s->mem_index](); - if (level) { - gen_op_enter_level(level, s->dflag); +#ifdef TARGET_X86_64 + if (CODE64(s)) { + ot = s->dflag ? OT_QUAD : OT_WORD; + opsize = 1 << ot; + + gen_op_movl_A0_ESP(); + gen_op_addq_A0_im(-opsize); + gen_op_movl_T1_A0(); + + /* push bp */ + gen_op_mov_TN_reg[OT_LONG][0][R_EBP](); + gen_op_st_T0_A0[ot + s->mem_index](); + if (level) { + gen_op_enter64_level(level, (ot == OT_QUAD)); + } + gen_op_mov_reg_T1[ot][R_EBP](); + gen_op_addl_T1_im( -esp_addend + (-opsize * level) ); + gen_op_mov_reg_T1[OT_QUAD][R_ESP](); + } else +#endif + { + ot = s->dflag + OT_WORD; + opsize = 2 << s->dflag; + + gen_op_movl_A0_ESP(); + gen_op_addl_A0_im(-opsize); + if (!s->ss32) + gen_op_andl_A0_ffff(); + gen_op_movl_T1_A0(); + if (s->addseg) + gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base)); + /* push bp */ + gen_op_mov_TN_reg[OT_LONG][0][R_EBP](); + gen_op_st_T0_A0[ot + s->mem_index](); + if (level) { + gen_op_enter_level(level, s->dflag); + } + gen_op_mov_reg_T1[ot][R_EBP](); + gen_op_addl_T1_im( -esp_addend + (-opsize * level) ); + gen_op_mov_reg_T1[OT_WORD + s->ss32][R_ESP](); } - gen_op_mov_reg_T1[ot][R_EBP](); - gen_op_addl_T1_im( -esp_addend + (-opsize * level) ); - gen_op_mov_reg_T1[OT_WORD + s->ss32][R_ESP](); } static void gen_exception(DisasContext *s, int trapno, target_ulong cur_eip) @@ -2181,18 +2239,12 @@ static void gen_eob(DisasContext *s) direct call to the next block may occur */ static void gen_jmp_tb(DisasContext *s, target_ulong eip, int tb_num) { - TranslationBlock *tb = s->tb; - if (s->jmp_opt) { - if (s->cc_op != CC_OP_DYNAMIC) + if (s->cc_op != CC_OP_DYNAMIC) { gen_op_set_cc_op(s->cc_op); - if (tb_num) - gen_op_goto_tb1(TBPARAM(tb)); - else - gen_op_goto_tb0(TBPARAM(tb)); - gen_jmp_im(eip); - gen_op_movl_T0_im((long)tb + tb_num); - gen_op_exit_tb(); + s->cc_op = CC_OP_DYNAMIC; + } + gen_goto_tb(s, tb_num, eip); s->is_jmp = 3; } else { gen_jmp_im(eip); @@ -2283,7 +2335,7 @@ static GenOpFunc2 *sse_op_table1[256][4] = { /* pure SSE operations */ [0x10] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movups, movupd, movss, movsd */ [0x11] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movups, movupd, movss, movsd */ - [0x12] = { SSE_SPECIAL, SSE_SPECIAL }, /* movlps, movlpd */ + [0x12] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movlps, movlpd, movsldup, movddup */ [0x13] = { SSE_SPECIAL, SSE_SPECIAL }, /* movlps, movlpd */ [0x14] = { gen_op_punpckldq_xmm, gen_op_punpcklqdq_xmm }, [0x15] = { gen_op_punpckhdq_xmm, gen_op_punpckhqdq_xmm }, @@ -2385,7 +2437,7 @@ static GenOpFunc2 *sse_op_table1[256][4] = { [0xed] = MMX_OP2(paddsw), [0xee] = MMX_OP2(pmaxsw), [0xef] = MMX_OP2(pxor), - [0xf0] = { NULL, NULL, NULL, SSE_SPECIAL }, /* lddqu (PNI) */ + [0xf0] = { NULL, NULL, NULL, SSE_SPECIAL }, /* lddqu */ [0xf1] = MMX_OP2(psllw), [0xf2] = MMX_OP2(pslld), [0xf3] = MMX_OP2(psllq), @@ -2512,8 +2564,8 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r) case 0x1e7: /* movntdq */ case 0x02b: /* movntps */ case 0x12b: /* movntps */ - case 0x2f0: /* lddqu */ - if (mod == 3) + case 0x3f0: /* lddqu */ + if (mod == 3) goto illegal_op; gen_lea_modrm(s, modrm, ®_addr, &offset_addr); gen_sto_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg])); @@ -2591,6 +2643,34 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r) offsetof(CPUX86State,xmm_regs[rm].XMM_Q(1))); } break; + case 0x212: /* movsldup */ + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_ldo_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg])); + } else { + rm = (modrm & 7) | REX_B(s); + gen_op_movl(offsetof(CPUX86State,xmm_regs[reg].XMM_L(0)), + offsetof(CPUX86State,xmm_regs[rm].XMM_L(0))); + gen_op_movl(offsetof(CPUX86State,xmm_regs[reg].XMM_L(2)), + offsetof(CPUX86State,xmm_regs[rm].XMM_L(2))); + } + gen_op_movl(offsetof(CPUX86State,xmm_regs[reg].XMM_L(1)), + offsetof(CPUX86State,xmm_regs[reg].XMM_L(0))); + gen_op_movl(offsetof(CPUX86State,xmm_regs[reg].XMM_L(3)), + offsetof(CPUX86State,xmm_regs[reg].XMM_L(2))); + break; + case 0x312: /* movddup */ + if (mod != 3) { + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_ldq_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0))); + } else { + rm = (modrm & 7) | REX_B(s); + gen_op_movq(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)), + offsetof(CPUX86State,xmm_regs[rm].XMM_Q(0))); + } + gen_op_movq(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(1)), + offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0))); + break; case 0x016: /* movhps */ case 0x116: /* movhpd */ if (mod != 3) { @@ -2826,6 +2906,7 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r) break; case 0xc4: /* pinsrw */ case 0x1c4: + s->rip_offset = 1; gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); val = ldub_code(s->pc++); if (b1) { @@ -2866,16 +2947,16 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r) break; case 0x2d6: /* movq2dq */ gen_op_enter_mmx(); - rm = (modrm & 7) | REX_B(s); - gen_op_movq(offsetof(CPUX86State,xmm_regs[rm].XMM_Q(0)), - offsetof(CPUX86State,fpregs[reg & 7].mmx)); - gen_op_movq_env_0(offsetof(CPUX86State,xmm_regs[rm].XMM_Q(1))); + rm = (modrm & 7); + gen_op_movq(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)), + offsetof(CPUX86State,fpregs[rm].mmx)); + gen_op_movq_env_0(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(1))); break; case 0x3d6: /* movdq2q */ gen_op_enter_mmx(); - rm = (modrm & 7); - gen_op_movq(offsetof(CPUX86State,fpregs[rm].mmx), - offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0))); + rm = (modrm & 7) | REX_B(s); + gen_op_movq(offsetof(CPUX86State,fpregs[reg & 7].mmx), + offsetof(CPUX86State,xmm_regs[rm].XMM_Q(0))); break; case 0xd7: /* pmovmskb */ case 0x1d7: @@ -2896,12 +2977,13 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r) } } else { /* generic MMX or SSE operation */ - if (b == 0xf7) { + switch(b) { + case 0xf7: /* maskmov : we must prepare A0 */ if (mod != 3) goto illegal_op; #ifdef TARGET_X86_64 - if (CODE64(s)) { + if (s->aflag == 2) { gen_op_movq_A0_reg[R_EDI](); } else #endif @@ -2911,13 +2993,21 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r) gen_op_andl_A0_ffff(); } gen_add_A0_ds_seg(s); + break; + case 0x70: /* pshufx insn */ + case 0xc6: /* pshufx insn */ + case 0xc2: /* compare insns */ + s->rip_offset = 1; + break; + default: + break; } if (is_xmm) { op1_offset = offsetof(CPUX86State,xmm_regs[reg]); if (mod != 3) { gen_lea_modrm(s, modrm, ®_addr, &offset_addr); op2_offset = offsetof(CPUX86State,xmm_t0); - if (b1 >= 2 && ((b >= 0x50 && b <= 0x5f) || + if (b1 >= 2 && ((b >= 0x50 && b <= 0x5f && b != 0x5b) || b == 0xc2)) { /* specific case for SSE single instructions */ if (b1 == 2) { @@ -3697,7 +3787,6 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) break; case 0xc8: /* enter */ { - /* XXX: long mode support */ int level; val = lduw_code(s->pc); s->pc += 2; @@ -3707,7 +3796,6 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) break; case 0xc9: /* leave */ /* XXX: exception not precise (ESP is updated before potential exception) */ - /* XXX: may be invalid for 16 bit in long mode */ if (CODE64(s)) { gen_op_mov_TN_reg[OT_QUAD][0][R_EBP](); gen_op_mov_reg_T0[OT_QUAD][R_ESP](); @@ -3926,7 +4014,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) else ot = dflag + OT_WORD; #ifdef TARGET_X86_64 - if (CODE64(s)) { + if (s->aflag == 2) { offset_addr = ldq_code(s->pc); s->pc += 8; if (offset_addr == (int32_t)offset_addr) @@ -3955,7 +4043,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) break; case 0xd7: /* xlat */ #ifdef TARGET_X86_64 - if (CODE64(s)) { + if (s->aflag == 2) { gen_op_movq_A0_reg[R_EBX](); gen_op_addq_A0_AL(); } else @@ -4229,16 +4317,9 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) case 0x08: /* flds */ case 0x0a: /* fsts */ case 0x0b: /* fstps */ - case 0x18: /* fildl */ - case 0x1a: /* fistl */ - case 0x1b: /* fistpl */ - case 0x28: /* fldl */ - case 0x2a: /* fstl */ - case 0x2b: /* fstpl */ - case 0x38: /* filds */ - case 0x3a: /* fists */ - case 0x3b: /* fistps */ - + case 0x18 ... 0x1b: /* fildl, fisttpl, fistl, fistpl */ + case 0x28 ... 0x2b: /* fldl, fisttpll, fstl, fstpl */ + case 0x38 ... 0x3b: /* filds, fisttps, fists, fistps */ switch(op & 7) { case 0: switch(op >> 4) { @@ -4257,6 +4338,20 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) break; } break; + case 1: + switch(op >> 4) { + case 1: + gen_op_fisttl_ST0_A0(); + break; + case 2: + gen_op_fisttll_ST0_A0(); + break; + case 3: + default: + gen_op_fistt_ST0_A0(); + } + gen_op_fpop(); + break; default: switch(op >> 4) { case 0: @@ -4779,6 +4874,8 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) val = ldsw_code(s->pc); s->pc += 2; gen_pop_T0(s); + if (CODE64(s) && s->dflag) + s->dflag = 2; gen_stack_update(s, val + (2 << s->dflag)); if (s->dflag == 0) gen_op_andl_T0_ffff(); @@ -4873,7 +4970,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) gen_op_movl_T1_imu(offset); } goto do_lcall; - case 0xe9: /* jmp */ + case 0xe9: /* jmp im */ if (dflag) tval = (int32_t)insn_get(s, OT_LONG); else @@ -5034,7 +5131,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) case 0x1ba: /* bt/bts/btr/btc Gv, im */ ot = dflag + OT_WORD; modrm = ldub_code(s->pc++); - op = ((modrm >> 3) & 7) | rex_r; + op = (modrm >> 3) & 7; mod = (modrm >> 6) & 3; rm = (modrm & 7) | REX_B(s); if (mod != 3) { @@ -5330,6 +5427,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) } break; case 0x131: /* rdtsc */ + gen_jmp_im(pc_start - s->cs_base); gen_op_rdtsc(); break; case 0x134: /* sysenter */ @@ -5470,26 +5568,69 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) modrm = ldub_code(s->pc++); mod = (modrm >> 6) & 3; op = (modrm >> 3) & 7; + rm = modrm & 7; switch(op) { case 0: /* sgdt */ - case 1: /* sidt */ if (mod == 3) goto illegal_op; gen_lea_modrm(s, modrm, ®_addr, &offset_addr); - if (op == 0) - gen_op_movl_T0_env(offsetof(CPUX86State,gdt.limit)); - else - gen_op_movl_T0_env(offsetof(CPUX86State,idt.limit)); + gen_op_movl_T0_env(offsetof(CPUX86State, gdt.limit)); gen_op_st_T0_A0[OT_WORD + s->mem_index](); gen_add_A0_im(s, 2); - if (op == 0) - gen_op_movtl_T0_env(offsetof(CPUX86State,gdt.base)); - else - gen_op_movtl_T0_env(offsetof(CPUX86State,idt.base)); + gen_op_movtl_T0_env(offsetof(CPUX86State, gdt.base)); if (!s->dflag) gen_op_andl_T0_im(0xffffff); gen_op_st_T0_A0[CODE64(s) + OT_LONG + s->mem_index](); break; + case 1: + if (mod == 3) { + switch (rm) { + case 0: /* monitor */ + if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) || + s->cpl != 0) + goto illegal_op; + gen_jmp_im(pc_start - s->cs_base); +#ifdef TARGET_X86_64 + if (s->aflag == 2) { + gen_op_movq_A0_reg[R_EBX](); + gen_op_addq_A0_AL(); + } else +#endif + { + gen_op_movl_A0_reg[R_EBX](); + gen_op_addl_A0_AL(); + if (s->aflag == 0) + gen_op_andl_A0_ffff(); + } + gen_add_A0_ds_seg(s); + gen_op_monitor(); + break; + case 1: /* mwait */ + if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) || + s->cpl != 0) + goto illegal_op; + if (s->cc_op != CC_OP_DYNAMIC) { + gen_op_set_cc_op(s->cc_op); + s->cc_op = CC_OP_DYNAMIC; + } + gen_jmp_im(s->pc - s->cs_base); + gen_op_mwait(); + gen_eob(s); + break; + default: + goto illegal_op; + } + } else { /* sidt */ + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + gen_op_movl_T0_env(offsetof(CPUX86State, idt.limit)); + gen_op_st_T0_A0[OT_WORD + s->mem_index](); + gen_add_A0_im(s, 2); + gen_op_movtl_T0_env(offsetof(CPUX86State, idt.base)); + if (!s->dflag) + gen_op_andl_T0_im(0xffffff); + gen_op_st_T0_A0[CODE64(s) + OT_LONG + s->mem_index](); + } + break; case 2: /* lgdt */ case 3: /* lidt */ if (mod == 3) @@ -5532,7 +5673,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) } else { if (mod == 3) { #ifdef TARGET_X86_64 - if (CODE64(s) && (modrm & 7) == 0) { + if (CODE64(s) && rm == 0) { /* swapgs */ gen_op_movtl_T0_env(offsetof(CPUX86State,segs[R_GS].base)); gen_op_movtl_T1_env(offsetof(CPUX86State,kernelgsbase)); @@ -5751,14 +5892,24 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) op = (modrm >> 3) & 7; switch(op) { case 0: /* fxsave */ - if (mod == 3 || !(s->cpuid_features & CPUID_FXSR)) + if (mod == 3 || !(s->cpuid_features & CPUID_FXSR) || + (s->flags & HF_EM_MASK)) goto illegal_op; + if (s->flags & HF_TS_MASK) { + gen_exception(s, EXCP07_PREX, pc_start - s->cs_base); + break; + } gen_lea_modrm(s, modrm, ®_addr, &offset_addr); gen_op_fxsave_A0((s->dflag == 2)); break; case 1: /* fxrstor */ - if (mod == 3 || !(s->cpuid_features & CPUID_FXSR)) + if (mod == 3 || !(s->cpuid_features & CPUID_FXSR) || + (s->flags & HF_EM_MASK)) goto illegal_op; + if (s->flags & HF_TS_MASK) { + gen_exception(s, EXCP07_PREX, pc_start - s->cs_base); + break; + } gen_lea_modrm(s, modrm, ®_addr, &offset_addr); gen_op_fxrstor_A0((s->dflag == 2)); break; @@ -5782,14 +5933,30 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) break; case 5: /* lfence */ case 6: /* mfence */ - case 7: /* sfence */ if ((modrm & 0xc7) != 0xc0 || !(s->cpuid_features & CPUID_SSE)) goto illegal_op; break; + case 7: /* sfence / clflush */ + if ((modrm & 0xc7) == 0xc0) { + /* sfence */ + if (!(s->cpuid_features & CPUID_SSE)) + goto illegal_op; + } else { + /* clflush */ + if (!(s->cpuid_features & CPUID_CLFLUSH)) + goto illegal_op; + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + } + break; default: goto illegal_op; } break; + case 0x10d: /* prefetch */ + modrm = ldub_code(s->pc++); + gen_lea_modrm(s, modrm, ®_addr, &offset_addr); + /* ignore for now */ + break; case 0x110 ... 0x117: case 0x128 ... 0x12f: case 0x150 ... 0x177: @@ -6225,6 +6392,7 @@ static inline int gen_intermediate_code_internal(CPUState *env, dc->mem_index = 1 * 4; } dc->cpuid_features = env->cpuid_features; + dc->cpuid_ext_features = env->cpuid_ext_features; #ifdef TARGET_X86_64 dc->lma = (flags >> HF_LMA_SHIFT) & 1; dc->code64 = (flags >> HF_CS64_SHIFT) & 1;