OSDN Git Service

better vm86 support - added iret - fixed push/pop fs/gs
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Sun, 30 Mar 2003 21:01:16 +0000 (21:01 +0000)
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Sun, 30 Mar 2003 21:01:16 +0000 (21:01 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@68 c046a42c-6fe2-441c-8c8c-71466251a162

op-i386.c
opc-i386.h
translate-i386.c

index dbf70bb..4330378 100644 (file)
--- 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 */
index 2a50e26..84e4144 100644 (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)
index 55e8a8d..4d8cbf3 100644 (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,