target-i386 fixes

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQEcBAABAgAGBQJW5vq+AAoJEK0ScMxN0Cebsw0IAJmNkj/H3frRNAGr75ZQZj8g
 /pY2V5aIPKIfIiTjtnnK5pxPNa48csiSzHiM8vjc9prsmrtmYKRh0lSWZh7zpHCu
 TraMpVYyQcIxqIvPM3nicdZOlLMsIfp0IbGJwlpNyIfR8jralKfN+Xqpe6HUOpRp
 T4/pygoeYnPjr3l0Q4t39XEka5r+gaODMs7cwNYSqQo7jknzycGcfNnm+2s4xj/S
 z4q2K7hG5OGaXS38+LUvY9v28BoxloEw12kpFbXPFIQD4tZMhU3SLFNWsYWI62/c
 NEWbGQ6fDJnjQv5mUGqjgipmOGPUQbN0CbA5atGRxpwQH3l3+xGgV2yI8x/p6Lo=
 =mkL8
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/rth/tags/pull-i386-20160314' into staging

target-i386 fixes

# gpg: Signature made Mon 14 Mar 2016 17:54:06 GMT using RSA key ID 4DD0279B
# gpg: Good signature from "Richard Henderson <rth7680@gmail.com>"
# gpg:                 aka "Richard Henderson <rth@redhat.com>"
# gpg:                 aka "Richard Henderson <rth@twiddle.net>"

* remotes/rth/tags/pull-i386-20160314:
  target-i386: Dump unknown opcodes with -d unimp
  target-i386: Fix inhibit irq mask handling
  target-i386: Use gen_nop_modrm for prefetch instructions
  target-i386: Fix addr16 prefix
  target-i386: Fix SMSW for 64-bit mode
  target-i386: Fix SMSW and LMSW from/to register
  target-i386: Avoid repeated calls to the bnd_jmp helper

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2016-03-15 10:08:12 +00:00
commit 9828f9b6c8

View File

@ -57,11 +57,17 @@
#endif #endif
/* For a switch indexed by MODRM, match all memory operands for a given OP. */ /* For a switch indexed by MODRM, match all memory operands for a given OP. */
#define CASE_MEM_OP(OP) \ #define CASE_MODRM_MEM_OP(OP) \
case (0 << 6) | (OP << 3) | 0 ... (0 << 6) | (OP << 3) | 7: \ case (0 << 6) | (OP << 3) | 0 ... (0 << 6) | (OP << 3) | 7: \
case (1 << 6) | (OP << 3) | 0 ... (1 << 6) | (OP << 3) | 7: \ case (1 << 6) | (OP << 3) | 0 ... (1 << 6) | (OP << 3) | 7: \
case (2 << 6) | (OP << 3) | 0 ... (2 << 6) | (OP << 3) | 7 case (2 << 6) | (OP << 3) | 0 ... (2 << 6) | (OP << 3) | 7
#define CASE_MODRM_OP(OP) \
case (0 << 6) | (OP << 3) | 0 ... (0 << 6) | (OP << 3) | 7: \
case (1 << 6) | (OP << 3) | 0 ... (1 << 6) | (OP << 3) | 7: \
case (2 << 6) | (OP << 3) | 0 ... (2 << 6) | (OP << 3) | 7: \
case (3 << 6) | (OP << 3) | 0 ... (3 << 6) | (OP << 3) | 7
//#define MACRO_TEST 1 //#define MACRO_TEST 1
/* global register indexes */ /* global register indexes */
@ -93,6 +99,7 @@ typedef struct DisasContext {
int prefix; int prefix;
TCGMemOp aflag; TCGMemOp aflag;
TCGMemOp dflag; TCGMemOp dflag;
target_ulong pc_start;
target_ulong pc; /* pc = eip + cs_base */ target_ulong pc; /* pc = eip + cs_base */
int is_jmp; /* 1 = means jump (stop translation), 2 means CPU int is_jmp; /* 1 = means jump (stop translation), 2 means CPU
static state change (stop translation) */ static state change (stop translation) */
@ -460,15 +467,15 @@ static void gen_lea_v_seg(DisasContext *s, TCGMemOp aflag, TCGv a0,
break; break;
case MO_16: case MO_16:
/* 16 bit address */ /* 16 bit address */
if (ovr_seg < 0) {
ovr_seg = def_seg;
}
tcg_gen_ext16u_tl(cpu_A0, a0); tcg_gen_ext16u_tl(cpu_A0, a0);
/* ADDSEG will only be false in 16-bit mode for LEA. */ a0 = cpu_A0;
if (!s->addseg) { if (ovr_seg < 0) {
if (s->addseg) {
ovr_seg = def_seg;
} else {
return; return;
} }
a0 = cpu_A0; }
break; break;
default: default:
tcg_abort(); tcg_abort();
@ -2362,6 +2369,30 @@ static void gen_exception(DisasContext *s, int trapno, target_ulong cur_eip)
s->is_jmp = DISAS_TB_JUMP; s->is_jmp = DISAS_TB_JUMP;
} }
/* Generate #UD for the current instruction. The assumption here is that
the instruction is known, but it isn't allowed in the current cpu mode. */
static void gen_illegal_opcode(DisasContext *s)
{
gen_exception(s, EXCP06_ILLOP, s->pc_start - s->cs_base);
}
/* Similarly, except that the assumption here is that we don't decode
the instruction at all -- either a missing opcode, an unimplemented
feature, or just a bogus instruction stream. */
static void gen_unknown_opcode(CPUX86State *env, DisasContext *s)
{
gen_illegal_opcode(s);
if (qemu_loglevel_mask(LOG_UNIMP)) {
target_ulong pc = s->pc_start, end = s->pc;
qemu_log("ILLOPC: " TARGET_FMT_lx ":", pc);
for (; pc < end; ++pc) {
qemu_log(" %02x", cpu_ldub_code(env, pc));
}
qemu_log("\n");
}
}
/* an interrupt is different from an exception because of the /* an interrupt is different from an exception because of the
privilege checks */ privilege checks */
static void gen_interrupt(DisasContext *s, int intno, static void gen_interrupt(DisasContext *s, int intno,
@ -2409,22 +2440,29 @@ static void gen_reset_hflag(DisasContext *s, uint32_t mask)
/* Clear BND registers during legacy branches. */ /* Clear BND registers during legacy branches. */
static void gen_bnd_jmp(DisasContext *s) static void gen_bnd_jmp(DisasContext *s)
{ {
/* Do nothing if BND prefix present, MPX is disabled, or if the /* Clear the registers only if BND prefix is missing, MPX is enabled,
BNDREGs are known to be in INIT state already. The helper and if the BNDREGs are known to be in use (non-zero) already.
itself will check BNDPRESERVE at runtime. */ The helper itself will check BNDPRESERVE at runtime. */
if ((s->prefix & PREFIX_REPNZ) == 0 if ((s->prefix & PREFIX_REPNZ) == 0
&& (s->flags & HF_MPX_EN_MASK) == 0 && (s->flags & HF_MPX_EN_MASK) != 0
&& (s->flags & HF_MPX_IU_MASK) == 0) { && (s->flags & HF_MPX_IU_MASK) != 0) {
gen_helper_bnd_jmp(cpu_env); gen_helper_bnd_jmp(cpu_env);
} }
} }
/* generate a generic end of block. Trace exception is also generated /* Generate an end of block. Trace exception is also generated if needed.
if needed */ If IIM, set HF_INHIBIT_IRQ_MASK if it isn't already set. */
static void gen_eob(DisasContext *s) static void gen_eob_inhibit_irq(DisasContext *s, bool inhibit)
{ {
gen_update_cc_op(s); gen_update_cc_op(s);
/* If several instructions disable interrupts, only the first does it. */
if (inhibit && !(s->flags & HF_INHIBIT_IRQ_MASK)) {
gen_set_hflag(s, HF_INHIBIT_IRQ_MASK);
} else {
gen_reset_hflag(s, HF_INHIBIT_IRQ_MASK); gen_reset_hflag(s, HF_INHIBIT_IRQ_MASK);
}
if (s->tb->flags & HF_RF_MASK) { if (s->tb->flags & HF_RF_MASK) {
gen_helper_reset_rf(cpu_env); gen_helper_reset_rf(cpu_env);
} }
@ -2438,6 +2476,12 @@ static void gen_eob(DisasContext *s)
s->is_jmp = DISAS_TB_JUMP; s->is_jmp = DISAS_TB_JUMP;
} }
/* End of block, resetting the inhibit irq flag. */
static void gen_eob(DisasContext *s)
{
gen_eob_inhibit_irq(s, false);
}
/* generate a jump to eip. No segment change must happen before as a /* generate a jump to eip. No segment change must happen before as a
direct call to the next block may occur */ direct call to the next block may occur */
static void gen_jmp_tb(DisasContext *s, target_ulong eip, int tb_num) static void gen_jmp_tb(DisasContext *s, target_ulong eip, int tb_num)
@ -2868,7 +2912,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
b1 = 0; b1 = 0;
sse_fn_epp = sse_op_table1[b][b1]; sse_fn_epp = sse_op_table1[b][b1];
if (!sse_fn_epp) { if (!sse_fn_epp) {
goto illegal_op; goto unknown_op;
} }
if ((b <= 0x5f && b >= 0x10) || b == 0xc6 || b == 0xc2) { if ((b <= 0x5f && b >= 0x10) || b == 0xc6 || b == 0xc2) {
is_xmm = 1; is_xmm = 1;
@ -2887,15 +2931,19 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
} }
if (s->flags & HF_EM_MASK) { if (s->flags & HF_EM_MASK) {
illegal_op: illegal_op:
gen_exception(s, EXCP06_ILLOP, pc_start - s->cs_base); gen_illegal_opcode(s);
return; return;
} }
if (is_xmm && !(s->flags & HF_OSFXSR_MASK)) if (is_xmm
if ((b != 0x38 && b != 0x3a) || (s->prefix & PREFIX_DATA)) && !(s->flags & HF_OSFXSR_MASK)
goto illegal_op; && ((b != 0x38 && b != 0x3a) || (s->prefix & PREFIX_DATA))) {
goto unknown_op;
}
if (b == 0x0e) { if (b == 0x0e) {
if (!(s->cpuid_ext2_features & CPUID_EXT2_3DNOW)) if (!(s->cpuid_ext2_features & CPUID_EXT2_3DNOW)) {
goto illegal_op; /* If we were fully decoding this we might use illegal_op. */
goto unknown_op;
}
/* femms */ /* femms */
gen_helper_emms(cpu_env); gen_helper_emms(cpu_env);
return; return;
@ -2920,8 +2968,9 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
b |= (b1 << 8); b |= (b1 << 8);
switch(b) { switch(b) {
case 0x0e7: /* movntq */ case 0x0e7: /* movntq */
if (mod == 3) if (mod == 3) {
goto illegal_op; goto illegal_op;
}
gen_lea_modrm(env, s, modrm); gen_lea_modrm(env, s, modrm);
gen_stq_env_A0(s, offsetof(CPUX86State, fpregs[reg].mmx)); gen_stq_env_A0(s, offsetof(CPUX86State, fpregs[reg].mmx));
break; break;
@ -3247,7 +3296,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
case 0x172: case 0x172:
case 0x173: case 0x173:
if (b1 >= 2) { if (b1 >= 2) {
goto illegal_op; goto unknown_op;
} }
val = cpu_ldub_code(env, s->pc++); val = cpu_ldub_code(env, s->pc++);
if (is_xmm) { if (is_xmm) {
@ -3266,7 +3315,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
sse_fn_epp = sse_op_table2[((b - 1) & 3) * 8 + sse_fn_epp = sse_op_table2[((b - 1) & 3) * 8 +
(((modrm >> 3)) & 7)][b1]; (((modrm >> 3)) & 7)][b1];
if (!sse_fn_epp) { if (!sse_fn_epp) {
goto illegal_op; goto unknown_op;
} }
if (is_xmm) { if (is_xmm) {
rm = (modrm & 7) | REX_B(s); rm = (modrm & 7) | REX_B(s);
@ -3490,12 +3539,12 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
reg = ((modrm >> 3) & 7) | rex_r; reg = ((modrm >> 3) & 7) | rex_r;
mod = (modrm >> 6) & 3; mod = (modrm >> 6) & 3;
if (b1 >= 2) { if (b1 >= 2) {
goto illegal_op; goto unknown_op;
} }
sse_fn_epp = sse_op_table6[b].op[b1]; sse_fn_epp = sse_op_table6[b].op[b1];
if (!sse_fn_epp) { if (!sse_fn_epp) {
goto illegal_op; goto unknown_op;
} }
if (!(s->cpuid_ext_features & sse_op_table6[b].ext_mask)) if (!(s->cpuid_ext_features & sse_op_table6[b].ext_mask))
goto illegal_op; goto illegal_op;
@ -3545,7 +3594,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
} }
} }
if (sse_fn_epp == SSE_SPECIAL) { if (sse_fn_epp == SSE_SPECIAL) {
goto illegal_op; goto unknown_op;
} }
tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset); tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset);
@ -3913,12 +3962,12 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
break; break;
default: default:
goto illegal_op; goto unknown_op;
} }
break; break;
default: default:
goto illegal_op; goto unknown_op;
} }
break; break;
@ -3930,12 +3979,12 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
reg = ((modrm >> 3) & 7) | rex_r; reg = ((modrm >> 3) & 7) | rex_r;
mod = (modrm >> 6) & 3; mod = (modrm >> 6) & 3;
if (b1 >= 2) { if (b1 >= 2) {
goto illegal_op; goto unknown_op;
} }
sse_fn_eppi = sse_op_table7[b].op[b1]; sse_fn_eppi = sse_op_table7[b].op[b1];
if (!sse_fn_eppi) { if (!sse_fn_eppi) {
goto illegal_op; goto unknown_op;
} }
if (!(s->cpuid_ext_features & sse_op_table7[b].ext_mask)) if (!(s->cpuid_ext_features & sse_op_table7[b].ext_mask))
goto illegal_op; goto illegal_op;
@ -4137,12 +4186,14 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
break; break;
default: default:
goto illegal_op; goto unknown_op;
} }
break; break;
default: default:
goto illegal_op; unknown_op:
gen_unknown_opcode(env, s);
return;
} }
} else { } else {
/* generic MMX or SSE operation */ /* generic MMX or SSE operation */
@ -4218,11 +4269,12 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
} }
switch(b) { switch(b) {
case 0x0f: /* 3DNow! data insns */ case 0x0f: /* 3DNow! data insns */
if (!(s->cpuid_ext2_features & CPUID_EXT2_3DNOW))
goto illegal_op;
val = cpu_ldub_code(env, s->pc++); val = cpu_ldub_code(env, s->pc++);
sse_fn_epp = sse_op_table5[val]; sse_fn_epp = sse_op_table5[val];
if (!sse_fn_epp) { if (!sse_fn_epp) {
goto unknown_op;
}
if (!(s->cpuid_ext2_features & CPUID_EXT2_3DNOW)) {
goto illegal_op; goto illegal_op;
} }
tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset); tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset);
@ -4242,7 +4294,7 @@ static void gen_sse(CPUX86State *env, DisasContext *s, int b,
/* compare insns */ /* compare insns */
val = cpu_ldub_code(env, s->pc++); val = cpu_ldub_code(env, s->pc++);
if (val >= 8) if (val >= 8)
goto illegal_op; goto unknown_op;
sse_fn_epp = sse_op_table4[val][b1]; sse_fn_epp = sse_op_table4[val][b1];
tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset); tcg_gen_addi_ptr(cpu_ptr0, cpu_env, op1_offset);
@ -4287,7 +4339,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
target_ulong next_eip, tval; target_ulong next_eip, tval;
int rex_w, rex_r; int rex_w, rex_r;
s->pc = pc_start; s->pc_start = s->pc = pc_start;
prefixes = 0; prefixes = 0;
s->override = -1; s->override = -1;
rex_w = -1; rex_w = -1;
@ -4400,7 +4452,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
b = 0x13a; b = 0x13a;
break; break;
default: /* Reserved for future use. */ default: /* Reserved for future use. */
goto illegal_op; goto unknown_op;
} }
} }
s->vex_v = (~vex3 >> 3) & 0xf; s->vex_v = (~vex3 >> 3) & 0xf;
@ -4750,7 +4802,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
} }
break; break;
default: default:
goto illegal_op; goto unknown_op;
} }
break; break;
@ -4763,7 +4815,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
rm = (modrm & 7) | REX_B(s); rm = (modrm & 7) | REX_B(s);
op = (modrm >> 3) & 7; op = (modrm >> 3) & 7;
if (op >= 2 && b == 0xfe) { if (op >= 2 && b == 0xfe) {
goto illegal_op; goto unknown_op;
} }
if (CODE64(s)) { if (CODE64(s)) {
if (op == 2 || op == 4) { if (op == 2 || op == 4) {
@ -4856,7 +4908,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_push_v(s, cpu_T0); gen_push_v(s, cpu_T0);
break; break;
default: default:
goto illegal_op; goto unknown_op;
} }
break; break;
@ -5171,17 +5223,16 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
ot = gen_pop_T0(s); ot = gen_pop_T0(s);
gen_movl_seg_T0(s, reg); gen_movl_seg_T0(s, reg);
gen_pop_update(s, ot); gen_pop_update(s, ot);
if (reg == R_SS) { /* Note that reg == R_SS in gen_movl_seg_T0 always sets is_jmp. */
/* if reg == SS, inhibit interrupts/trace. */
/* If several instructions disable interrupts, only the
_first_ does it */
gen_set_hflag(s, HF_INHIBIT_IRQ_MASK);
s->tf = 0;
}
if (s->is_jmp) { if (s->is_jmp) {
gen_jmp_im(s->pc - s->cs_base); gen_jmp_im(s->pc - s->cs_base);
if (reg == R_SS) {
s->tf = 0;
gen_eob_inhibit_irq(s, true);
} else {
gen_eob(s); gen_eob(s);
} }
}
break; break;
case 0x1a1: /* pop fs */ case 0x1a1: /* pop fs */
case 0x1a9: /* pop gs */ case 0x1a9: /* pop gs */
@ -5238,17 +5289,16 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
goto illegal_op; goto illegal_op;
gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0); gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 0);
gen_movl_seg_T0(s, reg); gen_movl_seg_T0(s, reg);
if (reg == R_SS) { /* Note that reg == R_SS in gen_movl_seg_T0 always sets is_jmp. */
/* if reg == SS, inhibit interrupts/trace */
/* If several instructions disable interrupts, only the
_first_ does it */
gen_set_hflag(s, HF_INHIBIT_IRQ_MASK);
s->tf = 0;
}
if (s->is_jmp) { if (s->is_jmp) {
gen_jmp_im(s->pc - s->cs_base); gen_jmp_im(s->pc - s->cs_base);
if (reg == R_SS) {
s->tf = 0;
gen_eob_inhibit_irq(s, true);
} else {
gen_eob(s); gen_eob(s);
} }
}
break; break;
case 0x8c: /* mov Gv, seg */ case 0x8c: /* mov Gv, seg */
modrm = cpu_ldub_code(env, s->pc++); modrm = cpu_ldub_code(env, s->pc++);
@ -5727,7 +5777,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_helper_fpop(cpu_env); gen_helper_fpop(cpu_env);
break; break;
default: default:
goto illegal_op; goto unknown_op;
} }
} else { } else {
/* register float ops */ /* register float ops */
@ -5751,7 +5801,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_helper_fwait(cpu_env); gen_helper_fwait(cpu_env);
break; break;
default: default:
goto illegal_op; goto unknown_op;
} }
break; break;
case 0x0c: /* grp d9/4 */ case 0x0c: /* grp d9/4 */
@ -5770,7 +5820,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_helper_fxam_ST0(cpu_env); gen_helper_fxam_ST0(cpu_env);
break; break;
default: default:
goto illegal_op; goto unknown_op;
} }
break; break;
case 0x0d: /* grp d9/5 */ case 0x0d: /* grp d9/5 */
@ -5805,7 +5855,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_helper_fldz_ST0(cpu_env); gen_helper_fldz_ST0(cpu_env);
break; break;
default: default:
goto illegal_op; goto unknown_op;
} }
} }
break; break;
@ -5905,7 +5955,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_helper_fpop(cpu_env); gen_helper_fpop(cpu_env);
break; break;
default: default:
goto illegal_op; goto unknown_op;
} }
break; break;
case 0x1c: case 0x1c:
@ -5923,7 +5973,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
case 4: /* fsetpm (287 only, just do nop here) */ case 4: /* fsetpm (287 only, just do nop here) */
break; break;
default: default:
goto illegal_op; goto unknown_op;
} }
break; break;
case 0x1d: /* fucomi */ case 0x1d: /* fucomi */
@ -5975,7 +6025,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_helper_fpop(cpu_env); gen_helper_fpop(cpu_env);
break; break;
default: default:
goto illegal_op; goto unknown_op;
} }
break; break;
case 0x38: /* ffreep sti, undocumented op */ case 0x38: /* ffreep sti, undocumented op */
@ -5990,7 +6040,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_op_mov_reg_v(MO_16, R_EAX, cpu_T0); gen_op_mov_reg_v(MO_16, R_EAX, cpu_T0);
break; break;
default: default:
goto illegal_op; goto unknown_op;
} }
break; break;
case 0x3d: /* fucomip */ case 0x3d: /* fucomip */
@ -6036,7 +6086,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
} }
break; break;
default: default:
goto illegal_op; goto unknown_op;
} }
} }
break; break;
@ -6507,7 +6557,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
val = cpu_ldub_code(env, s->pc++); val = cpu_ldub_code(env, s->pc++);
tcg_gen_movi_tl(cpu_T1, val); tcg_gen_movi_tl(cpu_T1, val);
if (op < 4) if (op < 4)
goto illegal_op; goto unknown_op;
op -= 4; op -= 4;
goto bt_op; goto bt_op;
case 0x1a3: /* bt Gv, Ev */ case 0x1a3: /* bt Gv, Ev */
@ -6773,27 +6823,14 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
} }
break; break;
case 0xfb: /* sti */ case 0xfb: /* sti */
if (!s->vm86) { if (s->vm86 ? s->iopl == 3 : s->cpl <= s->iopl) {
if (s->cpl <= s->iopl) {
gen_sti:
gen_helper_sti(cpu_env); gen_helper_sti(cpu_env);
/* interruptions are enabled only the first insn after sti */ /* interruptions are enabled only the first insn after sti */
/* If several instructions disable interrupts, only the
_first_ does it */
gen_set_hflag(s, HF_INHIBIT_IRQ_MASK);
/* give a chance to handle pending irqs */
gen_jmp_im(s->pc - s->cs_base); gen_jmp_im(s->pc - s->cs_base);
gen_eob(s); gen_eob_inhibit_irq(s, true);
} else { } else {
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
} }
} else {
if (s->iopl == 3) {
goto gen_sti;
} else {
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
}
}
break; break;
case 0x62: /* bound */ case 0x62: /* bound */
if (CODE64(s)) if (CODE64(s))
@ -7031,14 +7068,14 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
set_cc_op(s, CC_OP_EFLAGS); set_cc_op(s, CC_OP_EFLAGS);
break; break;
default: default:
goto illegal_op; goto unknown_op;
} }
break; break;
case 0x101: case 0x101:
modrm = cpu_ldub_code(env, s->pc++); modrm = cpu_ldub_code(env, s->pc++);
switch (modrm) { switch (modrm) {
CASE_MEM_OP(0): /* sgdt */ CASE_MODRM_MEM_OP(0): /* sgdt */
gen_svm_check_intercept(s, pc_start, SVM_EXIT_GDTR_READ); gen_svm_check_intercept(s, pc_start, SVM_EXIT_GDTR_READ);
gen_lea_modrm(env, s, modrm); gen_lea_modrm(env, s, modrm);
tcg_gen_ld32u_tl(cpu_T0, tcg_gen_ld32u_tl(cpu_T0,
@ -7094,7 +7131,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_eob(s); gen_eob(s);
break; break;
CASE_MEM_OP(1): /* sidt */ CASE_MODRM_MEM_OP(1): /* sidt */
gen_svm_check_intercept(s, pc_start, SVM_EXIT_IDTR_READ); gen_svm_check_intercept(s, pc_start, SVM_EXIT_IDTR_READ);
gen_lea_modrm(env, s, modrm); gen_lea_modrm(env, s, modrm);
tcg_gen_ld32u_tl(cpu_T0, cpu_env, offsetof(CPUX86State, idt.limit)); tcg_gen_ld32u_tl(cpu_T0, cpu_env, offsetof(CPUX86State, idt.limit));
@ -7240,7 +7277,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_helper_invlpga(cpu_env, tcg_const_i32(s->aflag - 1)); gen_helper_invlpga(cpu_env, tcg_const_i32(s->aflag - 1));
break; break;
CASE_MEM_OP(2): /* lgdt */ CASE_MODRM_MEM_OP(2): /* lgdt */
if (s->cpl != 0) { if (s->cpl != 0) {
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
break; break;
@ -7257,7 +7294,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
tcg_gen_st32_tl(cpu_T1, cpu_env, offsetof(CPUX86State, gdt.limit)); tcg_gen_st32_tl(cpu_T1, cpu_env, offsetof(CPUX86State, gdt.limit));
break; break;
CASE_MEM_OP(3): /* lidt */ CASE_MODRM_MEM_OP(3): /* lidt */
if (s->cpl != 0) { if (s->cpl != 0) {
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
break; break;
@ -7274,17 +7311,19 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
tcg_gen_st32_tl(cpu_T1, cpu_env, offsetof(CPUX86State, idt.limit)); tcg_gen_st32_tl(cpu_T1, cpu_env, offsetof(CPUX86State, idt.limit));
break; break;
CASE_MEM_OP(4): /* smsw */ CASE_MODRM_OP(4): /* smsw */
gen_svm_check_intercept(s, pc_start, SVM_EXIT_READ_CR0); gen_svm_check_intercept(s, pc_start, SVM_EXIT_READ_CR0);
#if defined TARGET_X86_64 && defined HOST_WORDS_BIGENDIAN tcg_gen_ld_tl(cpu_T0, cpu_env, offsetof(CPUX86State, cr[0]));
tcg_gen_ld32u_tl(cpu_T0, cpu_env, offsetof(CPUX86State, cr[0]) + 4); if (CODE64(s)) {
#else mod = (modrm >> 6) & 3;
tcg_gen_ld32u_tl(cpu_T0, cpu_env, offsetof(CPUX86State, cr[0])); ot = (mod != 3 ? MO_16 : s->dflag);
#endif } else {
gen_ldst_modrm(env, s, modrm, MO_16, OR_TMP0, 1); ot = MO_16;
}
gen_ldst_modrm(env, s, modrm, ot, OR_TMP0, 1);
break; break;
CASE_MEM_OP(6): /* lmsw */ CASE_MODRM_OP(6): /* lmsw */
if (s->cpl != 0) { if (s->cpl != 0) {
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
break; break;
@ -7296,7 +7335,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_eob(s); gen_eob(s);
break; break;
CASE_MEM_OP(7): /* invlpg */ CASE_MODRM_MEM_OP(7): /* invlpg */
if (s->cpl != 0) { if (s->cpl != 0) {
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
break; break;
@ -7343,7 +7382,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
break; break;
default: default:
goto illegal_op; goto unknown_op;
} }
break; break;
@ -7467,7 +7506,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
case 3: /* prefetchnt0 */ case 3: /* prefetchnt0 */
if (mod == 3) if (mod == 3)
goto illegal_op; goto illegal_op;
gen_lea_modrm(env, s, modrm); gen_nop_modrm(env, s, modrm);
/* nothing more to do */ /* nothing more to do */
break; break;
default: /* nop (multi byte) */ default: /* nop (multi byte) */
@ -7712,7 +7751,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
} }
break; break;
default: default:
goto illegal_op; goto unknown_op;
} }
} }
break; break;
@ -7778,7 +7817,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
case 0x1ae: case 0x1ae:
modrm = cpu_ldub_code(env, s->pc++); modrm = cpu_ldub_code(env, s->pc++);
switch (modrm) { switch (modrm) {
CASE_MEM_OP(0): /* fxsave */ CASE_MODRM_MEM_OP(0): /* fxsave */
if (!(s->cpuid_features & CPUID_FXSR) if (!(s->cpuid_features & CPUID_FXSR)
|| (prefixes & PREFIX_LOCK)) { || (prefixes & PREFIX_LOCK)) {
goto illegal_op; goto illegal_op;
@ -7791,7 +7830,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_helper_fxsave(cpu_env, cpu_A0); gen_helper_fxsave(cpu_env, cpu_A0);
break; break;
CASE_MEM_OP(1): /* fxrstor */ CASE_MODRM_MEM_OP(1): /* fxrstor */
if (!(s->cpuid_features & CPUID_FXSR) if (!(s->cpuid_features & CPUID_FXSR)
|| (prefixes & PREFIX_LOCK)) { || (prefixes & PREFIX_LOCK)) {
goto illegal_op; goto illegal_op;
@ -7804,7 +7843,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_helper_fxrstor(cpu_env, cpu_A0); gen_helper_fxrstor(cpu_env, cpu_A0);
break; break;
CASE_MEM_OP(2): /* ldmxcsr */ CASE_MODRM_MEM_OP(2): /* ldmxcsr */
if ((s->flags & HF_EM_MASK) || !(s->flags & HF_OSFXSR_MASK)) { if ((s->flags & HF_EM_MASK) || !(s->flags & HF_OSFXSR_MASK)) {
goto illegal_op; goto illegal_op;
} }
@ -7817,7 +7856,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_helper_ldmxcsr(cpu_env, cpu_tmp2_i32); gen_helper_ldmxcsr(cpu_env, cpu_tmp2_i32);
break; break;
CASE_MEM_OP(3): /* stmxcsr */ CASE_MODRM_MEM_OP(3): /* stmxcsr */
if ((s->flags & HF_EM_MASK) || !(s->flags & HF_OSFXSR_MASK)) { if ((s->flags & HF_EM_MASK) || !(s->flags & HF_OSFXSR_MASK)) {
goto illegal_op; goto illegal_op;
} }
@ -7830,7 +7869,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_op_st_v(s, MO_32, cpu_T0, cpu_A0); gen_op_st_v(s, MO_32, cpu_T0, cpu_A0);
break; break;
CASE_MEM_OP(4): /* xsave */ CASE_MODRM_MEM_OP(4): /* xsave */
if ((s->cpuid_ext_features & CPUID_EXT_XSAVE) == 0 if ((s->cpuid_ext_features & CPUID_EXT_XSAVE) == 0
|| (prefixes & (PREFIX_LOCK | PREFIX_DATA || (prefixes & (PREFIX_LOCK | PREFIX_DATA
| PREFIX_REPZ | PREFIX_REPNZ))) { | PREFIX_REPZ | PREFIX_REPNZ))) {
@ -7842,7 +7881,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_helper_xsave(cpu_env, cpu_A0, cpu_tmp1_i64); gen_helper_xsave(cpu_env, cpu_A0, cpu_tmp1_i64);
break; break;
CASE_MEM_OP(5): /* xrstor */ CASE_MODRM_MEM_OP(5): /* xrstor */
if ((s->cpuid_ext_features & CPUID_EXT_XSAVE) == 0 if ((s->cpuid_ext_features & CPUID_EXT_XSAVE) == 0
|| (prefixes & (PREFIX_LOCK | PREFIX_DATA || (prefixes & (PREFIX_LOCK | PREFIX_DATA
| PREFIX_REPZ | PREFIX_REPNZ))) { | PREFIX_REPZ | PREFIX_REPNZ))) {
@ -7859,7 +7898,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_eob(s); gen_eob(s);
break; break;
CASE_MEM_OP(6): /* xsaveopt / clwb */ CASE_MODRM_MEM_OP(6): /* xsaveopt / clwb */
if (prefixes & PREFIX_LOCK) { if (prefixes & PREFIX_LOCK) {
goto illegal_op; goto illegal_op;
} }
@ -7883,7 +7922,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
} }
break; break;
CASE_MEM_OP(7): /* clflush / clflushopt */ CASE_MODRM_MEM_OP(7): /* clflush / clflushopt */
if (prefixes & PREFIX_LOCK) { if (prefixes & PREFIX_LOCK) {
goto illegal_op; goto illegal_op;
} }
@ -7934,7 +7973,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
} }
break; break;
} }
goto illegal_op; goto unknown_op;
case 0xf8: /* sfence / pcommit */ case 0xf8: /* sfence / pcommit */
if (prefixes & PREFIX_DATA) { if (prefixes & PREFIX_DATA) {
@ -7956,7 +7995,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
break; break;
default: default:
goto illegal_op; goto unknown_op;
} }
break; break;
@ -7965,8 +8004,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
mod = (modrm >> 6) & 3; mod = (modrm >> 6) & 3;
if (mod == 3) if (mod == 3)
goto illegal_op; goto illegal_op;
gen_lea_modrm(env, s, modrm); gen_nop_modrm(env, s, modrm);
/* ignore for now */
break; break;
case 0x1aa: /* rsm */ case 0x1aa: /* rsm */
gen_svm_check_intercept(s, pc_start, SVM_EXIT_RSM); gen_svm_check_intercept(s, pc_start, SVM_EXIT_RSM);
@ -8013,7 +8051,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_sse(env, s, b, pc_start, rex_r); gen_sse(env, s, b, pc_start, rex_r);
break; break;
default: default:
goto illegal_op; goto unknown_op;
} }
/* lock generation */ /* lock generation */
if (s->prefix & PREFIX_LOCK) if (s->prefix & PREFIX_LOCK)
@ -8023,7 +8061,13 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
if (s->prefix & PREFIX_LOCK) if (s->prefix & PREFIX_LOCK)
gen_helper_unlock(); gen_helper_unlock();
/* XXX: ensure that no lock was generated */ /* XXX: ensure that no lock was generated */
gen_exception(s, EXCP06_ILLOP, pc_start - s->cs_base); gen_illegal_opcode(s);
return s->pc;
unknown_op:
if (s->prefix & PREFIX_LOCK)
gen_helper_unlock();
/* XXX: ensure that no lock was generated */
gen_unknown_opcode(env, s);
return s->pc; return s->pc;
} }