better vm86 support - added iret - fixed push/pop fs/gs

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@68 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
bellard 2003-03-30 21:01:16 +00:00
parent f7341ff400
commit f631ef9bd2
3 changed files with 168 additions and 7 deletions

View File

@ -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 */

View File

@ -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)

View File

@ -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,