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,