[FAST486]
[reactos.git] / reactos / lib / fast486 / opcodes.c
index 101361b..859009c 100644 (file)
@@ -254,11 +254,11 @@ Fast486OpcodeHandlers[FAST486_NUM_OPCODE_HANDLERS] =
     Fast486OpcodeAad,                   /* 0xD5 */
     Fast486OpcodeSalc,                  /* 0xD6 */
     Fast486OpcodeXlat,                  /* 0xD7 */
-    Fast486FpuOpcodeD8DC,               /* 0xD8 - 0xDF */
+    Fast486FpuOpcodeD8,                 /* 0xD8 - 0xDF */
     Fast486FpuOpcodeD9,
     Fast486FpuOpcodeDA,
     Fast486FpuOpcodeDB,
-    Fast486FpuOpcodeD8DC,
+    Fast486FpuOpcodeDC,
     Fast486FpuOpcodeDD,
     Fast486FpuOpcodeDE,
     Fast486FpuOpcodeDF,
@@ -754,7 +754,7 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeClearInt)
     if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
     {
         /* Check IOPL */
-        if (State->Flags.Iopl >= State->SegmentRegs[FAST486_REG_CS].Dpl)
+        if (State->Flags.Iopl >= Fast486GetCurrentPrivLevel(State))
         {
             /* Clear the interrupt flag */
             State->Flags.If = FALSE;
@@ -789,7 +789,7 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeSetInt)
     if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
     {
         /* Check IOPL */
-        if (State->Flags.Iopl >= State->SegmentRegs[FAST486_REG_CS].Dpl)
+        if (State->Flags.Iopl >= Fast486GetCurrentPrivLevel(State))
         {
             /* Set the interrupt flag */
             State->Flags.If = TRUE;
@@ -2635,7 +2635,11 @@ FAST486_OPCODE_HANDLER(Fast486OpcodePopSs)
     }
 
     /* Call the internal API */
-    Fast486LoadSegment(State, FAST486_REG_SS, LOWORD(NewSelector));
+    if (Fast486LoadSegment(State, FAST486_REG_SS, LOWORD(NewSelector)))
+    {
+        /* Inhibit all interrupts until the next instruction */
+        State->DoNotInterrupt = TRUE;
+    }
 }
 
 FAST486_OPCODE_HANDLER(Fast486OpcodeSbbByteModrm)
@@ -3828,16 +3832,13 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeMovModrm)
 
 FAST486_OPCODE_HANDLER(Fast486OpcodeMovStoreSeg)
 {
-    BOOLEAN OperandSize, AddressSize;
+    BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
     FAST486_MOD_REG_RM ModRegRm;
 
-    OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
-
     /* Make sure this is the right instruction */
     ASSERT(Opcode == 0x8C);
 
     TOGGLE_ADSIZE(AddressSize);
-    TOGGLE_OPSIZE(OperandSize);
 
     /* Get the operands */
     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
@@ -3853,20 +3854,10 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeMovStoreSeg)
         return;
     }
 
-    if (OperandSize)
-    {
-        Fast486WriteModrmDwordOperands(State,
-                                       &ModRegRm,
-                                       FALSE,
-                                       State->SegmentRegs[ModRegRm.Register].Selector);
-    }
-    else
-    {
-        Fast486WriteModrmWordOperands(State,
-                                      &ModRegRm,
-                                      FALSE,
-                                      State->SegmentRegs[ModRegRm.Register].Selector);
-    }
+    Fast486WriteModrmWordOperands(State,
+                                  &ModRegRm,
+                                  FALSE,
+                                  State->SegmentRegs[ModRegRm.Register].Selector);
 }
 
 FAST486_OPCODE_HANDLER(Fast486OpcodeLea)
@@ -3917,16 +3908,14 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeLea)
 
 FAST486_OPCODE_HANDLER(Fast486OpcodeMovLoadSeg)
 {
-    BOOLEAN OperandSize, AddressSize;
+    BOOLEAN AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
     FAST486_MOD_REG_RM ModRegRm;
-
-    OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
+    USHORT Selector;
 
     /* Make sure this is the right instruction */
     ASSERT(Opcode == 0x8E);
 
     TOGGLE_ADSIZE(AddressSize);
-    TOGGLE_OPSIZE(OperandSize);
 
     /* Get the operands */
     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
@@ -3943,29 +3932,22 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeMovLoadSeg)
         return;
     }
 
-    if (OperandSize)
+    if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Selector))
     {
-        ULONG Selector;
-
-        if (!Fast486ReadModrmDwordOperands(State, &ModRegRm, NULL, &Selector))
-        {
-            /* Exception occurred */
-            return;
-        }
-
-        Fast486LoadSegment(State, ModRegRm.Register, LOWORD(Selector));
+        /* Exception occurred */
+        return;
     }
-    else
-    {
-        USHORT Selector;
 
-        if (!Fast486ReadModrmWordOperands(State, &ModRegRm, NULL, &Selector))
-        {
-            /* Exception occurred */
-            return;
-        }
+    if (!Fast486LoadSegment(State, ModRegRm.Register, Selector))
+    {
+        /* Exception occurred */
+        return;
+    }
 
-        Fast486LoadSegment(State, ModRegRm.Register, Selector);
+    if ((INT)ModRegRm.Register == FAST486_REG_SS)
+    {
+        /* Inhibit all interrupts until the next instruction */
+        State->DoNotInterrupt = TRUE;
     }
 }
 
@@ -4061,6 +4043,15 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeCallAbs)
         return;
     }
 
+    if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
+    {
+        if (!Fast486ProcessGate(State, Segment, Offset, TRUE))
+        {
+            /* Gate processed or exception occurred */
+            return;
+        }
+    }
+
     /* Push the current code segment selector */
     if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector))
     {
@@ -4089,8 +4080,19 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeCallAbs)
 
 FAST486_OPCODE_HANDLER(Fast486OpcodeWait)
 {
-    // TODO: NOT IMPLEMENTED
-    UNIMPLEMENTED;
+#ifndef FAST486_NO_FPU
+
+    if ((!State->FpuControl.Pm && State->FpuStatus.Pe)
+        || (!State->FpuControl.Um && State->FpuStatus.Ue)
+        || (!State->FpuControl.Om && State->FpuStatus.Oe)
+        || (!State->FpuControl.Zm && State->FpuStatus.Ze)
+        || (!State->FpuControl.Dm && State->FpuStatus.De)
+        || (!State->FpuControl.Im && State->FpuStatus.Ie))
+    {
+        Fast486FpuException(State);
+    }
+
+#endif
 }
 
 FAST486_OPCODE_HANDLER(Fast486OpcodePushFlags)
@@ -4116,7 +4118,7 @@ FAST486_OPCODE_HANDLER(Fast486OpcodePushFlags)
 FAST486_OPCODE_HANDLER(Fast486OpcodePopFlags)
 {
     BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
-    INT Cpl = Fast486GetCurrentPrivLevel(State);
+    UINT Cpl = Fast486GetCurrentPrivLevel(State);
     FAST486_FLAGS_REG NewFlags;
 
     NO_LOCK_PREFIX();
@@ -4240,11 +4242,6 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeLdsLes)
         {
             UCHAR BopCode;
 
-#ifndef FAST486_NO_PREFETCH
-            /* Invalidate the prefetch since BOP handlers can alter the memory */
-            State->PrefetchValid = FALSE;
-#endif
-
             /* Fetch the BOP code */
             if (!Fast486FetchByte(State, &BopCode))
             {
@@ -4252,6 +4249,11 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeLdsLes)
                 return;
             }
 
+#ifndef FAST486_NO_PREFETCH
+            /* Invalidate the prefetch since BOP handlers can alter the memory */
+            State->PrefetchValid = FALSE;
+#endif
+
             /* Call the BOP handler */
             State->BopCallback(State, BopCode);
 
@@ -4261,10 +4263,7 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeLdsLes)
              * changes the CS:IP, the interrupt handler won't execute and the
              * stack pointer will never be restored.
              */
-            if (State->IntStatus == FAST486_INT_EXECUTE)
-            {
-                State->IntStatus = FAST486_INT_DELAYED;
-            }
+            State->DoNotInterrupt = TRUE;
 
             return;
         }
@@ -4370,16 +4369,24 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeEnter)
     if (NestingLevel > 0) Fast486StackPush(State, FramePointer.Long);
 
     /* Set EBP to the frame pointer */
-    State->GeneralRegs[FAST486_REG_EBP] = FramePointer;
+    if (Size) State->GeneralRegs[FAST486_REG_EBP].Long = FramePointer.Long;
+    else State->GeneralRegs[FAST486_REG_EBP].LowWord = FramePointer.LowWord;
 
     /* Reserve space for the frame */
-    if (Size) State->GeneralRegs[FAST486_REG_ESP].Long -= (ULONG)FrameSize;
-    else State->GeneralRegs[FAST486_REG_ESP].LowWord -= FrameSize;
+    if (State->SegmentRegs[FAST486_REG_SS].Size)
+    {
+        State->GeneralRegs[FAST486_REG_ESP].Long -= (ULONG)FrameSize;
+    }
+    else
+    {
+        State->GeneralRegs[FAST486_REG_ESP].LowWord -= FrameSize;
+    }
 }
 
 FAST486_OPCODE_HANDLER(Fast486OpcodeLeave)
 {
     BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
+    ULONG Value;
 
     /* Make sure this is the right instruction */
     ASSERT(Opcode == 0xC9);
@@ -4387,26 +4394,22 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeLeave)
     NO_LOCK_PREFIX();
     TOGGLE_OPSIZE(Size);
 
-    if (Size)
+    if (State->SegmentRegs[FAST486_REG_SS].Size)
     {
         /* Set the stack pointer (ESP) to the base pointer (EBP) */
         State->GeneralRegs[FAST486_REG_ESP].Long = State->GeneralRegs[FAST486_REG_EBP].Long;
-
-        /* Pop the saved base pointer from the stack */
-        Fast486StackPop(State, &State->GeneralRegs[FAST486_REG_EBP].Long);
     }
     else
     {
-        ULONG Value;
-
         /* Set the stack pointer (SP) to the base pointer (BP) */
         State->GeneralRegs[FAST486_REG_ESP].LowWord = State->GeneralRegs[FAST486_REG_EBP].LowWord;
+    }
 
-        /* Pop the saved base pointer from the stack */
-        if (Fast486StackPop(State, &Value))
-        {
-            State->GeneralRegs[FAST486_REG_EBP].LowWord = LOWORD(Value);
-        }
+    /* Pop the saved base pointer from the stack */
+    if (Fast486StackPop(State, &Value))
+    {
+        if (Size) State->GeneralRegs[FAST486_REG_EBP].Long = Value;
+        else State->GeneralRegs[FAST486_REG_EBP].LowWord = LOWORD(Value);
     }
 }
 
@@ -4450,6 +4453,63 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeRetFar)
         return;
     }
 
+    if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) && !State->Flags.Vm)
+    {
+        UINT i;
+        UINT OldCpl = Fast486GetCurrentPrivLevel(State);
+        ULONG StackPtr;
+        ULONG StackSel;
+
+        if (GET_SEGMENT_RPL(Segment) > OldCpl)
+        {
+            /* Pop ESP */
+            if (!Fast486StackPop(State, &StackPtr))
+            {
+                /* Exception */
+                return;
+            }
+
+            /* Pop SS */
+            if (!Fast486StackPop(State, &StackSel))
+            {
+                /* Exception */
+                return;
+            }
+        }
+
+        /* Update the CPL */
+        State->Cpl = GET_SEGMENT_RPL(Segment);
+
+        if (State->Cpl > OldCpl)
+        {
+            /* Load new SS */
+            if (!Fast486LoadSegment(State, FAST486_REG_SS, StackSel))
+            {
+                /* Exception */
+                return;
+            }
+
+            /* Set ESP */
+            if (Size) State->GeneralRegs[FAST486_REG_ESP].Long = StackPtr;
+            else State->GeneralRegs[FAST486_REG_ESP].LowWord = LOWORD(StackPtr);
+
+            /* Check segment security */
+            for (i = 0; i < FAST486_NUM_SEG_REGS; i++)
+            {
+                /* Don't check CS or SS */
+                if ((i == FAST486_REG_CS) || (i == FAST486_REG_SS)) continue;
+
+                if ((State->Cpl > State->SegmentRegs[i].Dpl)
+                    && (!State->SegmentRegs[i].Executable
+                    || !State->SegmentRegs[i].DirConf))
+                {
+                    /* Load the NULL descriptor in the segment */
+                    if (!Fast486LoadSegment(State, i, 0)) return;
+                }
+            }
+        }
+    }
+
     /* Load new (E)IP, and if necessary, pop the parameters */
     if (Size)
     {
@@ -4467,6 +4527,14 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeInt)
 {
     UCHAR IntNum;
 
+    /* Check for V86 mode */
+    if (State->Flags.Vm && (State->Flags.Iopl != 3))
+    {
+        /* Call the V86 monitor */
+        Fast486Exception(State, FAST486_EXCEPTION_GP);
+        return;
+    }
+
     switch (Opcode)
     {
         case 0xCC:  // INT 3
@@ -4523,6 +4591,17 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeIret)
     NO_LOCK_PREFIX();
     TOGGLE_OPSIZE(Size);
 
+    /* Check if this is a nested task return */
+    if (State->Flags.Nt && (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE))
+    {
+        /* Clear the NT flag of the current task */
+        State->Flags.Nt = FALSE;
+
+        /* Switch to the old task */
+        Fast486TaskSwitch(State, FAST486_TASK_RETURN, 0);
+        return;
+    }
+
     /* Pop EIP */
     if (!Fast486StackPop(State, &InstPtr))
     {
@@ -4547,7 +4626,7 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeIret)
     /* Check for protected mode */
     if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
     {
-        INT Cpl = Fast486GetCurrentPrivLevel(State);
+        UINT OldCpl = Fast486GetCurrentPrivLevel(State);
 
         if (State->Flags.Vm)
         {
@@ -4582,20 +4661,12 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeIret)
             return;
         }
 
-        if (State->Flags.Nt)
-        {
-            /* Nested task return */
-
-            UNIMPLEMENTED;
-            return;
-        }
-
         if (NewFlags.Vm)
         {
             /* Return to VM86 mode */
             ULONG Es, Ds, Fs, Gs;
 
-            /* Pop ESP, SS, ES, FS, GS */
+            /* Pop ESP, SS, ES, DS, FS, GS */
             if (!Fast486StackPop(State, &StackPtr)) return;
             if (!Fast486StackPop(State, &StackSel)) return;
             if (!Fast486StackPop(State, &Es)) return;
@@ -4633,7 +4704,7 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeIret)
         if (Size) State->InstPtr.Long = InstPtr;
         else State->InstPtr.LowWord = LOWORD(InstPtr);
 
-        if (GET_SEGMENT_RPL(CodeSel) > Cpl)
+        if (GET_SEGMENT_RPL(CodeSel) > OldCpl)
         {
             /* Pop ESP */
             if (!Fast486StackPop(State, &StackPtr))
@@ -4648,7 +4719,22 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeIret)
                 /* Exception */
                 return;
             }
+        }
+
+        /* Update the CPL */
+        State->Cpl = GET_SEGMENT_RPL(CodeSel);
 
+        /* Set the new flags */
+        if (Size) State->Flags.Long = NewFlags.Long & PROT_MODE_FLAGS_MASK;
+        else State->Flags.LowWord = NewFlags.LowWord & PROT_MODE_FLAGS_MASK;
+        State->Flags.AlwaysSet = TRUE;
+
+        /* Set additional flags */
+        if (OldCpl <= State->Flags.Iopl) State->Flags.If = NewFlags.If;
+        if (OldCpl == 0) State->Flags.Iopl = NewFlags.Iopl;
+
+        if (State->Cpl > OldCpl)
+        {
             /* Load new SS */
             if (!Fast486LoadSegment(State, FAST486_REG_SS, StackSel))
             {
@@ -4659,21 +4745,6 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeIret)
             /* Set ESP */
             if (Size) State->GeneralRegs[FAST486_REG_ESP].Long = StackPtr;
             else State->GeneralRegs[FAST486_REG_ESP].LowWord = LOWORD(StackPtr);
-        }
-
-        /* Set the new flags */
-        if (Size) State->Flags.Long = NewFlags.Long & PROT_MODE_FLAGS_MASK;
-        else State->Flags.LowWord = NewFlags.LowWord & PROT_MODE_FLAGS_MASK;
-        State->Flags.AlwaysSet = TRUE;
-
-        /* Set additional flags */
-        if (Cpl <= State->Flags.Iopl) State->Flags.If = NewFlags.If;
-        if (Cpl == 0) State->Flags.Iopl = NewFlags.Iopl;
-
-        if (GET_SEGMENT_RPL(CodeSel) > Cpl)
-        {
-            /* Update the CPL */
-            Cpl = Fast486GetCurrentPrivLevel(State);
 
             /* Check segment security */
             for (i = 0; i < FAST486_NUM_SEG_REGS; i++)
@@ -4681,7 +4752,7 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeIret)
                 /* Don't check CS or SS */
                 if ((i == FAST486_REG_CS) || (i == FAST486_REG_SS)) continue;
 
-                if ((Cpl > State->SegmentRegs[i].Dpl)
+                if ((State->Cpl > State->SegmentRegs[i].Dpl)
                     && (!State->SegmentRegs[i].Executable
                     || !State->SegmentRegs[i].DirConf))
                 {
@@ -5006,6 +5077,15 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeJmpAbs)
         return;
     }
 
+    if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
+    {
+        if (!Fast486ProcessGate(State, Segment, Offset, FALSE))
+        {
+            /* Gate processed or exception occurred */
+            return;
+        }
+    }
+
     /* Load the new CS */
     if (!Fast486LoadSegment(State, FAST486_REG_CS, Segment))
     {
@@ -5179,7 +5259,7 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeMovOffsetAl)
 FAST486_OPCODE_HANDLER(Fast486OpcodeMovOffsetEax)
 {
     BOOLEAN OperandSize, AddressSize;
-    
+
     OperandSize = AddressSize = State->SegmentRegs[FAST486_REG_CS].Size;
 
     /* Make sure this is the right instruction */
@@ -5752,7 +5832,7 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeScas)
             || (!AddressSize && (State->GeneralRegs[FAST486_REG_ECX].LowWord == 0)))
         {
             /* Do nothing */
-            return; 
+            return;
         }
     }