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);
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));
+ }
}
}
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)
{
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]();
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 {
{
#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
{
#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
{
#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
{
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
{
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)
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);
/* 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 },
[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),
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]));
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) {
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) {
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:
}
} 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
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) {
break;
case 0xc8: /* enter */
{
- /* XXX: long mode support */
int level;
val = lduw_code(s->pc);
s->pc += 2;
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]();
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)
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
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) {
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:
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();
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
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) {
}
break;
case 0x131: /* rdtsc */
+ gen_jmp_im(pc_start - s->cs_base);
gen_op_rdtsc();
break;
case 0x134: /* sysenter */
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)
} 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));
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;
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:
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;