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);
*offset_ptr = disp;
}
+static void gen_nop_modrm(DisasContext *s, int modrm)
+{
+ int mod, rm, base, code;
+
+ mod = (modrm >> 6) & 3;
+ if (mod == 3)
+ return;
+ rm = modrm & 7;
+
+ if (s->aflag) {
+
+ base = rm;
+
+ if (base == 4) {
+ code = ldub_code(s->pc++);
+ base = (code & 7);
+ }
+
+ switch (mod) {
+ case 0:
+ if (base == 5) {
+ s->pc += 4;
+ }
+ break;
+ case 1:
+ s->pc++;
+ break;
+ default:
+ case 2:
+ s->pc += 4;
+ break;
+ }
+ } else {
+ switch (mod) {
+ case 0:
+ if (rm == 6) {
+ s->pc += 2;
+ }
+ break;
+ case 1:
+ s->pc++;
+ break;
+ default:
+ case 2:
+ s->pc += 2;
+ break;
+ }
+ }
+}
+
/* used for LEA and MOV AX, mem */
static void gen_add_A0_ds_seg(DisasContext *s)
{
}
/* an interrupt is different from an exception because of the
- priviledge checks */
+ privilege checks */
static void gen_interrupt(DisasContext *s, int intno,
target_ulong cur_eip, target_ulong next_eip)
{
gen_sto_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg]));
break;
case 0x6e: /* movd mm, ea */
- gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 0);
- gen_op_movl_mm_T0_mmx(offsetof(CPUX86State,fpregs[reg].mmx));
+#ifdef TARGET_X86_64
+ if (s->dflag == 2) {
+ gen_ldst_modrm(s, modrm, OT_QUAD, OR_TMP0, 0);
+ gen_op_movq_mm_T0_mmx(offsetof(CPUX86State,fpregs[reg].mmx));
+ } else
+#endif
+ {
+ gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 0);
+ gen_op_movl_mm_T0_mmx(offsetof(CPUX86State,fpregs[reg].mmx));
+ }
break;
case 0x16e: /* movd xmm, ea */
- gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 0);
- gen_op_movl_mm_T0_xmm(offsetof(CPUX86State,xmm_regs[reg]));
+#ifdef TARGET_X86_64
+ if (s->dflag == 2) {
+ gen_ldst_modrm(s, modrm, OT_QUAD, OR_TMP0, 0);
+ gen_op_movq_mm_T0_xmm(offsetof(CPUX86State,xmm_regs[reg]));
+ } else
+#endif
+ {
+ gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 0);
+ gen_op_movl_mm_T0_xmm(offsetof(CPUX86State,xmm_regs[reg]));
+ }
break;
case 0x6f: /* movq mm, ea */
if (mod != 3) {
offsetof(CPUX86State,xmm_regs[reg].XMM_L(3)));
break;
case 0x7e: /* movd ea, mm */
- gen_op_movl_T0_mm_mmx(offsetof(CPUX86State,fpregs[reg].mmx));
- gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 1);
+#ifdef TARGET_X86_64
+ if (s->dflag == 2) {
+ gen_op_movq_T0_mm_mmx(offsetof(CPUX86State,fpregs[reg].mmx));
+ gen_ldst_modrm(s, modrm, OT_QUAD, OR_TMP0, 1);
+ } else
+#endif
+ {
+ gen_op_movl_T0_mm_mmx(offsetof(CPUX86State,fpregs[reg].mmx));
+ gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 1);
+ }
break;
case 0x17e: /* movd ea, xmm */
- gen_op_movl_T0_mm_xmm(offsetof(CPUX86State,xmm_regs[reg]));
- gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 1);
+#ifdef TARGET_X86_64
+ if (s->dflag == 2) {
+ gen_op_movq_T0_mm_xmm(offsetof(CPUX86State,xmm_regs[reg]));
+ gen_ldst_modrm(s, modrm, OT_QUAD, OR_TMP0, 1);
+ } else
+#endif
+ {
+ gen_op_movl_T0_mm_xmm(offsetof(CPUX86State,xmm_regs[reg]));
+ gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 1);
+ }
break;
case 0x27e: /* movq xmm, ea */
if (mod != 3) {
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:
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) {
mod = (modrm >> 6) & 3;
if (mod == 3)
goto illegal_op;
+ gen_jmp_im(pc_start - s->cs_base);
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
if (CODE64(s))
goto illegal_op;
val = ldub_code(s->pc++);
- gen_op_aam(val);
- s->cc_op = CC_OP_LOGICB;
+ if (val == 0) {
+ gen_exception(s, EXCP00_DIVZ, pc_start - s->cs_base);
+ } else {
+ gen_op_aam(val);
+ s->cc_op = CC_OP_LOGICB;
+ }
break;
case 0xd5: /* aad */
if (CODE64(s))
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));
gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
/* nothing more to do */
break;
- default:
- goto illegal_op;
+ default: /* nop (multi byte) */
+ gen_nop_modrm(s, modrm);
+ break;
}
break;
+ case 0x119 ... 0x11f: /* nop (multi byte) */
+ modrm = ldub_code(s->pc++);
+ gen_nop_modrm(s, modrm);
+ break;
case 0x120: /* mov reg, crN */
case 0x122: /* mov crN, reg */
if (s->cpl != 0) {
gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
/* ignore for now */
break;
+ case 0x1aa: /* rsm */
+ if (!(s->flags & HF_SMM_MASK))
+ 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_rsm();
+ gen_eob(s);
+ break;
case 0x110 ... 0x117:
case 0x128 ... 0x12f:
case 0x150 ... 0x177:
opc_ptr = opc_buf + opc_buf_len;
/* live_flags contains the flags needed by the next instructions
- in the code. At the end of the bloc, we consider that all the
+ in the code. At the end of the block, we consider that all the
flags are live. */
live_flags = CC_OSZAPC;
while (opc_ptr > opc_buf) {
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;