aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--op-i386.c99
-rw-r--r--opc-i386.h8
-rw-r--r--translate-i386.c68
3 files changed, 168 insertions, 7 deletions
diff --git a/op-i386.c b/op-i386.c
index dbf70bb590..43303784da 100644
--- a/op-i386.c
+++ b/op-i386.c
@@ -611,6 +611,35 @@ void OPPROTO op_into(void)
}
}
+/* XXX: add IOPL/CPL tests */
+void OPPROTO op_cli(void)
+{
+ raise_exception(EXCP0D_GPF);
+}
+
+/* XXX: add IOPL/CPL tests */
+void OPPROTO op_sti(void)
+{
+ raise_exception(EXCP0D_GPF);
+}
+
+/* vm86plus instructions */
+
+void OPPROTO op_cli_vm(void)
+{
+ env->eflags &= ~VIF_MASK;
+}
+
+void OPPROTO op_sti_vm(void)
+{
+ env->eflags |= VIF_MASK;
+ if (env->eflags & VIP_MASK) {
+ EIP = PARAM1;
+ raise_exception(EXCP0D_GPF);
+ }
+ FORCE_RET();
+}
+
void OPPROTO op_boundw(void)
{
int low, high, v;
@@ -1234,7 +1263,8 @@ void OPPROTO op_set_cc_op(void)
CC_OP = PARAM1;
}
-#define FL_UPDATE_MASK (TF_MASK | AC_MASK | ID_MASK)
+#define FL_UPDATE_MASK32 (TF_MASK | AC_MASK | ID_MASK)
+#define FL_UPDATE_MASK16 (TF_MASK)
void OPPROTO op_movl_eflags_T0(void)
{
@@ -1243,7 +1273,56 @@ void OPPROTO op_movl_eflags_T0(void)
CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
DF = 1 - (2 * ((eflags >> 10) & 1));
/* we also update some system flags as in user mode */
- env->eflags = (env->eflags & ~FL_UPDATE_MASK) | (eflags & FL_UPDATE_MASK);
+ env->eflags = (env->eflags & ~FL_UPDATE_MASK32) | (eflags & FL_UPDATE_MASK32);
+}
+
+void OPPROTO op_movw_eflags_T0(void)
+{
+ int eflags;
+ eflags = T0;
+ CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
+ DF = 1 - (2 * ((eflags >> 10) & 1));
+ /* we also update some system flags as in user mode */
+ env->eflags = (env->eflags & ~FL_UPDATE_MASK16) | (eflags & FL_UPDATE_MASK16);
+}
+
+/* vm86 version */
+void OPPROTO op_movw_eflags_T0_vm(void)
+{
+ int eflags;
+ eflags = T0;
+ CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
+ DF = 1 - (2 * ((eflags >> 10) & 1));
+ /* we also update some system flags as in user mode */
+ env->eflags = (env->eflags & ~(FL_UPDATE_MASK16 | VIF_MASK)) |
+ (eflags & FL_UPDATE_MASK16);
+ if (eflags & IF_MASK) {
+ env->eflags |= VIF_MASK;
+ if (env->eflags & VIP_MASK) {
+ EIP = PARAM1;
+ raise_exception(EXCP0D_GPF);
+ }
+ }
+ FORCE_RET();
+}
+
+void OPPROTO op_movl_eflags_T0_vm(void)
+{
+ int eflags;
+ eflags = T0;
+ CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
+ DF = 1 - (2 * ((eflags >> 10) & 1));
+ /* we also update some system flags as in user mode */
+ env->eflags = (env->eflags & ~(FL_UPDATE_MASK32 | VIF_MASK)) |
+ (eflags & FL_UPDATE_MASK32);
+ if (eflags & IF_MASK) {
+ env->eflags |= VIF_MASK;
+ if (env->eflags & VIP_MASK) {
+ EIP = PARAM1;
+ raise_exception(EXCP0D_GPF);
+ }
+ }
+ FORCE_RET();
}
/* XXX: compute only O flag */
@@ -1263,6 +1342,18 @@ void OPPROTO op_movl_T0_eflags(void)
T0 = eflags;
}
+/* vm86 version */
+void OPPROTO op_movl_T0_eflags_vm(void)
+{
+ int eflags;
+ eflags = cc_table[CC_OP].compute_all();
+ eflags |= (DF & DF_MASK);
+ eflags |= env->eflags & ~(VM_MASK | RF_MASK | IF_MASK);
+ if (env->eflags & VIF_MASK)
+ eflags |= IF_MASK;
+ T0 = eflags;
+}
+
void OPPROTO op_cld(void)
{
DF = 1;
@@ -1377,7 +1468,9 @@ CCTable cc_table[CC_OP_NB] = {
[CC_OP_SARL] = { compute_all_sarl, compute_c_shll },
};
-/* floating point support */
+/* floating point support. Some of the code for complicated x87
+ functions comes from the LGPL'ed x86 emulator found in the Willows
+ TWIN windows emulator. */
#ifdef USE_X86LDOUBLE
/* use long double functions */
diff --git a/opc-i386.h b/opc-i386.h
index 2a50e26a75..84e41440f1 100644
--- a/opc-i386.h
+++ b/opc-i386.h
@@ -232,6 +232,10 @@ DEF(jmp_im, 1)
DEF(int_im, 1)
DEF(int3, 1)
DEF(into, 0)
+DEF(cli, 0)
+DEF(sti, 0)
+DEF(cli_vm, 0)
+DEF(sti_vm, 1)
DEF(boundw, 0)
DEF(boundl, 0)
DEF(cmpxchg8b, 0)
@@ -551,8 +555,12 @@ DEF(setle_T0_cc, 0)
DEF(xor_T0_1, 0)
DEF(set_cc_op, 1)
DEF(movl_eflags_T0, 0)
+DEF(movw_eflags_T0, 0)
+DEF(movw_eflags_T0_vm, 1)
+DEF(movl_eflags_T0_vm, 1)
DEF(movb_eflags_T0, 0)
DEF(movl_T0_eflags, 0)
+DEF(movl_T0_eflags_vm, 0)
DEF(cld, 0)
DEF(std, 0)
DEF(clc, 0)
diff --git a/translate-i386.c b/translate-i386.c
index 55e8a8dde6..4d8cbf391a 100644
--- a/translate-i386.c
+++ b/translate-i386.c
@@ -1919,7 +1919,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
break;
case 0x1a0: /* push fs */
case 0x1a8: /* push gs */
- gen_op_movl_T0_seg(((b >> 3) & 7) + R_FS);
+ gen_op_movl_T0_seg((b >> 3) & 7);
gen_push_T0(s);
break;
case 0x07: /* pop es */
@@ -1932,7 +1932,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
case 0x1a1: /* pop fs */
case 0x1a9: /* pop gs */
gen_pop_T0(s);
- gen_movl_seg_T0(s, ((b >> 3) & 7) + R_FS);
+ gen_movl_seg_T0(s, (b >> 3) & 7);
gen_pop_update(s);
break;
@@ -2833,6 +2833,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
s->is_jmp = 1;
break;
case 0xca: /* lret im */
+ /* XXX: not restartable */
val = ldsw(s->pc);
s->pc += 2;
/* pop offset */
@@ -2853,6 +2854,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
s->is_jmp = 1;
break;
case 0xcb: /* lret */
+ /* XXX: not restartable */
/* pop offset */
gen_pop_T0(s);
if (s->dflag == 0)
@@ -2865,6 +2867,35 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
gen_pop_update(s);
s->is_jmp = 1;
break;
+ case 0xcf: /* iret */
+ /* XXX: not restartable */
+ /* pop offset */
+ gen_pop_T0(s);
+ if (s->dflag == 0)
+ gen_op_andl_T0_ffff();
+ gen_op_jmp_T0();
+ gen_pop_update(s);
+ /* pop selector */
+ gen_pop_T0(s);
+ gen_movl_seg_T0(s, R_CS);
+ gen_pop_update(s);
+ /* pop eflags */
+ gen_pop_T0(s);
+ if (s->dflag) {
+ if (s->vm86)
+ gen_op_movl_eflags_T0_vm(pc_start - s->cs_base);
+ else
+ gen_op_movl_eflags_T0();
+ } else {
+ if (s->vm86)
+ gen_op_movw_eflags_T0_vm(pc_start - s->cs_base);
+ else
+ gen_op_movw_eflags_T0();
+ }
+ gen_pop_update(s);
+ s->cc_op = CC_OP_EFLAGS;
+ s->is_jmp = 1;
+ break;
case 0xe8: /* call im */
{
unsigned int next_eip;
@@ -2978,12 +3009,25 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
case 0x9c: /* pushf */
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
- gen_op_movl_T0_eflags();
+ if (s->vm86)
+ gen_op_movl_T0_eflags_vm();
+ else
+ gen_op_movl_T0_eflags();
gen_push_T0(s);
break;
case 0x9d: /* popf */
gen_pop_T0(s);
- gen_op_movl_eflags_T0();
+ if (s->dflag) {
+ if (s->vm86)
+ gen_op_movl_eflags_T0_vm(pc_start - s->cs_base);
+ else
+ gen_op_movl_eflags_T0();
+ } else {
+ if (s->vm86)
+ gen_op_movw_eflags_T0_vm(pc_start - s->cs_base);
+ else
+ gen_op_movw_eflags_T0();
+ }
gen_pop_update(s);
s->cc_op = CC_OP_EFLAGS;
break;
@@ -3159,6 +3203,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
gen_op_set_cc_op(s->cc_op);
gen_op_into();
break;
+ case 0xfa: /* cli */
+ if (s->vm86)
+ gen_op_cli_vm();
+ else
+ gen_op_cli();
+ break;
+ case 0xfb: /* sti */
+ if (s->vm86)
+ gen_op_sti_vm(pc_start - s->cs_base);
+ else
+ gen_op_sti();
+ break;
case 0x62: /* bound */
ot = dflag ? OT_LONG : OT_WORD;
modrm = ldub(s->pc++);
@@ -3308,6 +3364,7 @@ static uint16_t opc_read_flags[NB_OPS] = {
[INDEX_op_setle_T0_subl] = CC_O | CC_S | CC_Z,
[INDEX_op_movl_T0_eflags] = CC_OSZAPC,
+ [INDEX_op_movl_T0_eflags_vm] = CC_OSZAPC,
[INDEX_op_cmc] = CC_C,
[INDEX_op_salc] = CC_C,
@@ -3356,7 +3413,10 @@ static uint16_t opc_write_flags[NB_OPS] = {
[INDEX_op_daa] = CC_OSZAPC,
[INDEX_op_movb_eflags_T0] = CC_S | CC_Z | CC_A | CC_P | CC_C,
+ [INDEX_op_movw_eflags_T0] = CC_OSZAPC,
+ [INDEX_op_movw_eflags_T0_vm] = CC_OSZAPC,
[INDEX_op_movl_eflags_T0] = CC_OSZAPC,
+ [INDEX_op_movl_eflags_T0_vm] = CC_OSZAPC,
[INDEX_op_clc] = CC_C,
[INDEX_op_stc] = CC_C,
[INDEX_op_cmc] = CC_C,