}
}
+/* 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;
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)
{
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 */
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;
[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 */
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 */
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;
s->is_jmp = 1;
break;
case 0xca: /* lret im */
+ /* XXX: not restartable */
val = ldsw(s->pc);
s->pc += 2;
/* pop offset */
s->is_jmp = 1;
break;
case 0xcb: /* lret */
+ /* XXX: not restartable */
/* pop offset */
gen_pop_T0(s);
if (s->dflag == 0)
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;
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;
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++);
[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,
[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,