iret and int fix for vm86 - added undefined instructions for real and vm86 modes...
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Thu, 13 Nov 2003 01:43:28 +0000 (01:43 +0000)
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Thu, 13 Nov 2003 01:43:28 +0000 (01:43 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@454 c046a42c-6fe2-441c-8c8c-71466251a162

target-i386/translate.c

index ab4fe09e6b75cdf4915fd646d6847986db23f982..7ce8f4bdee8c32986c761c8992e27ba5e6619461 100644 (file)
@@ -749,6 +749,43 @@ static GenOpFunc *gen_op_out_DX_T0[3] = {
     gen_op_outl_DX_T0,
 };
 
+static GenOpFunc *gen_op_in[3] = {
+    gen_op_inb_T0_T1,
+    gen_op_inw_T0_T1,
+    gen_op_inl_T0_T1,
+};
+
+static GenOpFunc *gen_op_out[3] = {
+    gen_op_outb_T0_T1,
+    gen_op_outw_T0_T1,
+    gen_op_outl_T0_T1,
+};
+
+static GenOpFunc *gen_check_io_T0[3] = {
+    gen_op_check_iob_T0,
+    gen_op_check_iow_T0,
+    gen_op_check_iol_T0,
+};
+
+static GenOpFunc *gen_check_io_DX[3] = {
+    gen_op_check_iob_DX,
+    gen_op_check_iow_DX,
+    gen_op_check_iol_DX,
+};
+
+static void gen_check_io(DisasContext *s, int ot, int use_dx, int cur_eip)
+{
+    if (s->pe && (s->cpl > s->iopl || s->vm86)) {
+        if (s->cc_op != CC_OP_DYNAMIC)
+            gen_op_set_cc_op(s->cc_op);
+        gen_op_jmp_im(cur_eip);
+        if (use_dx)
+            gen_check_io_DX[ot]();
+        else
+            gen_check_io_T0[ot]();
+    }
+}
+
 static inline void gen_movs(DisasContext *s, int ot)
 {
     gen_string_movl_A0_ESI(s);
@@ -912,18 +949,6 @@ GEN_REPZ(outs)
 GEN_REPZ2(scas)
 GEN_REPZ2(cmps)
 
-static GenOpFunc *gen_op_in[3] = {
-    gen_op_inb_T0_T1,
-    gen_op_inw_T0_T1,
-    gen_op_inl_T0_T1,
-};
-
-static GenOpFunc *gen_op_out[3] = {
-    gen_op_outb_T0_T1,
-    gen_op_outw_T0_T1,
-    gen_op_outl_T0_T1,
-};
-
 enum {
     JCC_O,
     JCC_B,
@@ -3221,36 +3246,28 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
         break;
     case 0x6c: /* insS */
     case 0x6d:
-        if (s->pe && (s->cpl > s->iopl || s->vm86)) {
-            /* NOTE: even for (E)CX = 0 the exception is raised */
-            gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+        if ((b & 1) == 0)
+            ot = OT_BYTE;
+        else
+            ot = dflag ? OT_LONG : OT_WORD;
+        gen_check_io(s, ot, 1, pc_start - s->cs_base);
+        if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
+            gen_repz_ins(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
         } else {
-            if ((b & 1) == 0)
-                ot = OT_BYTE;
-            else
-                ot = dflag ? OT_LONG : OT_WORD;
-            if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
-                gen_repz_ins(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
-            } else {
-                gen_ins(s, ot);
-            }
+            gen_ins(s, ot);
         }
         break;
     case 0x6e: /* outsS */
     case 0x6f:
-        if (s->pe && (s->cpl > s->iopl || s->vm86)) {
-            /* NOTE: even for (E)CX = 0 the exception is raised */
-            gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+        if ((b & 1) == 0)
+            ot = OT_BYTE;
+        else
+            ot = dflag ? OT_LONG : OT_WORD;
+        gen_check_io(s, ot, 1, pc_start - s->cs_base);
+        if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
+            gen_repz_outs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
         } else {
-            if ((b & 1) == 0)
-                ot = OT_BYTE;
-            else
-                ot = dflag ? OT_LONG : OT_WORD;
-            if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
-                gen_repz_outs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
-            } else {
-                gen_outs(s, ot);
-            }
+            gen_outs(s, ot);
         }
         break;
 
@@ -3258,61 +3275,49 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
         /* port I/O */
     case 0xe4:
     case 0xe5:
-        if (s->pe && (s->cpl > s->iopl || s->vm86)) {
-            gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
-        } else {
-            if ((b & 1) == 0)
-                ot = OT_BYTE;
-            else
-                ot = dflag ? OT_LONG : OT_WORD;
-            val = ldub_code(s->pc++);
-            gen_op_movl_T0_im(val);
-            gen_op_in[ot]();
-            gen_op_mov_reg_T1[ot][R_EAX]();
-        }
+        if ((b & 1) == 0)
+            ot = OT_BYTE;
+        else
+            ot = dflag ? OT_LONG : OT_WORD;
+        val = ldub_code(s->pc++);
+        gen_op_movl_T0_im(val);
+        gen_check_io(s, ot, 0, pc_start - s->cs_base);
+        gen_op_in[ot]();
+        gen_op_mov_reg_T1[ot][R_EAX]();
         break;
     case 0xe6:
     case 0xe7:
-        if (s->pe && (s->cpl > s->iopl || s->vm86)) {
-            gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
-        } else {
-            if ((b & 1) == 0)
-                ot = OT_BYTE;
-            else
-                ot = dflag ? OT_LONG : OT_WORD;
-            val = ldub_code(s->pc++);
-            gen_op_movl_T0_im(val);
-            gen_op_mov_TN_reg[ot][1][R_EAX]();
-            gen_op_out[ot]();
-        }
+        if ((b & 1) == 0)
+            ot = OT_BYTE;
+        else
+            ot = dflag ? OT_LONG : OT_WORD;
+        val = ldub_code(s->pc++);
+        gen_op_movl_T0_im(val);
+        gen_check_io(s, ot, 0, pc_start - s->cs_base);
+        gen_op_mov_TN_reg[ot][1][R_EAX]();
+        gen_op_out[ot]();
         break;
     case 0xec:
     case 0xed:
-        if (s->pe && (s->cpl > s->iopl || s->vm86)) {
-            gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
-        } else {
-            if ((b & 1) == 0)
-                ot = OT_BYTE;
-            else
-                ot = dflag ? OT_LONG : OT_WORD;
-            gen_op_mov_TN_reg[OT_WORD][0][R_EDX]();
-            gen_op_in[ot]();
-            gen_op_mov_reg_T1[ot][R_EAX]();
-        }
+        if ((b & 1) == 0)
+            ot = OT_BYTE;
+        else
+            ot = dflag ? OT_LONG : OT_WORD;
+        gen_op_mov_TN_reg[OT_WORD][0][R_EDX]();
+        gen_check_io(s, ot, 0, pc_start - s->cs_base);
+        gen_op_in[ot]();
+        gen_op_mov_reg_T1[ot][R_EAX]();
         break;
     case 0xee:
     case 0xef:
-        if (s->pe && (s->cpl > s->iopl || s->vm86)) {
-            gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
-        } else {
-            if ((b & 1) == 0)
-                ot = OT_BYTE;
-            else
-                ot = dflag ? OT_LONG : OT_WORD;
-            gen_op_mov_TN_reg[OT_WORD][0][R_EDX]();
-            gen_op_mov_TN_reg[ot][1][R_EAX]();
-            gen_op_out[ot]();
-        }
+        if ((b & 1) == 0)
+            ot = OT_BYTE;
+        else
+            ot = dflag ? OT_LONG : OT_WORD;
+        gen_op_mov_TN_reg[OT_WORD][0][R_EDX]();
+        gen_check_io(s, ot, 0, pc_start - s->cs_base);
+        gen_op_mov_TN_reg[ot][1][R_EAX]();
+        gen_op_out[ot]();
         break;
 
         /************************/
@@ -3370,8 +3375,13 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
             /* real mode */
             gen_op_iret_real(s->dflag);
             s->cc_op = CC_OP_EFLAGS;
-        } else if (s->vm86 && s->iopl != 3) {
-            gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+        } else if (s->vm86) {
+            if (s->iopl != 3) {
+                gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+            } else {
+                gen_op_iret_real(s->dflag);
+                s->cc_op = CC_OP_EFLAGS;
+            }
         } else {
             if (s->cc_op != CC_OP_DYNAMIC)
                 gen_op_set_cc_op(s->cc_op);
@@ -3675,11 +3685,11 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
         break;
     case 0xcd: /* int N */
         val = ldub_code(s->pc++);
-        /* XXX: add error code for vm86 GPF */
-        if (!s->vm86)
-            gen_interrupt(s, val, pc_start - s->cs_base, s->pc - s->cs_base);
-        else
+        if (s->vm86 && s->iopl != 3) {
             gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); 
+        } else {
+            gen_interrupt(s, val, pc_start - s->cs_base, s->pc - s->cs_base);
+        }
         break;
     case 0xce: /* into */
         if (s->cc_op != CC_OP_DYNAMIC)
@@ -3799,6 +3809,8 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
         op = (modrm >> 3) & 7;
         switch(op) {
         case 0: /* sldt */
+            if (!s->pe || s->vm86)
+                goto illegal_op;
             gen_op_movl_T0_env(offsetof(CPUX86State,ldt.selector));
             ot = OT_WORD;
             if (mod == 3)
@@ -3806,6 +3818,8 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
             gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
             break;
         case 2: /* lldt */
+            if (!s->pe || s->vm86)
+                goto illegal_op;
             if (s->cpl != 0) {
                 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
             } else {
@@ -3815,6 +3829,8 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
             }
             break;
         case 1: /* str */
+            if (!s->pe || s->vm86)
+                goto illegal_op;
             gen_op_movl_T0_env(offsetof(CPUX86State,tr.selector));
             ot = OT_WORD;
             if (mod == 3)
@@ -3822,6 +3838,8 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
             gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
             break;
         case 3: /* ltr */
+            if (!s->pe || s->vm86)
+                goto illegal_op;
             if (s->cpl != 0) {
                 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
             } else {
@@ -3832,6 +3850,17 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
             break;
         case 4: /* verr */
         case 5: /* verw */
+            if (!s->pe || s->vm86)
+                goto illegal_op;
+            gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
+            if (s->cc_op != CC_OP_DYNAMIC)
+                gen_op_set_cc_op(s->cc_op);
+            if (op == 4)
+                gen_op_verr();
+            else
+                gen_op_verw();
+            s->cc_op = CC_OP_EFLAGS;
+            break;
         default:
             goto illegal_op;
         }
@@ -3908,6 +3937,31 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start)
             goto illegal_op;
         }
         break;
+    case 0x63: /* arpl */
+        if (!s->pe || s->vm86)
+            goto illegal_op;
+        ot = dflag ? OT_LONG : OT_WORD;
+        modrm = ldub_code(s->pc++);
+        reg = (modrm >> 3) & 7;
+        mod = (modrm >> 6) & 3;
+        rm = modrm & 7;
+        if (mod != 3) {
+            gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
+            gen_op_ld_T0_A0[ot + s->mem_index]();
+        } else {
+            gen_op_mov_TN_reg[ot][0][rm]();
+        }
+        if (s->cc_op != CC_OP_DYNAMIC)
+            gen_op_set_cc_op(s->cc_op);
+        gen_op_arpl();
+        s->cc_op = CC_OP_EFLAGS;
+        if (mod != 3) {
+            gen_op_st_T0_A0[ot + s->mem_index]();
+        } else {
+            gen_op_mov_reg_T0[ot][rm]();
+        }
+        gen_op_arpl_update();
+        break;
     case 0x102: /* lar */
     case 0x103: /* lsl */
         if (!s->pe || s->vm86)