[FAST486]
[reactos.git] / reactos / lib / fast486 / opgroups.c
index d812fcf..65dd686 100644 (file)
@@ -2,7 +2,7 @@
  * Fast486 386/486 CPU Emulation Library
  * opgroups.c
  *
- * Copyright (C) 2014 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
+ * Copyright (C) 2015 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -70,6 +70,7 @@ Fast486ArithmeticOperation(PFAST486_STATE State,
         case 1:
         {
             Result = FirstValue | SecondValue;
+            State->Flags.Cf = State->Flags.Of = FALSE;
             break;
         }
 
@@ -112,6 +113,7 @@ Fast486ArithmeticOperation(PFAST486_STATE State,
         case 4:
         {
             Result = FirstValue & SecondValue;
+            State->Flags.Cf = State->Flags.Of = FALSE;
             break;
         }
 
@@ -134,6 +136,7 @@ Fast486ArithmeticOperation(PFAST486_STATE State,
         case 6:
         {
             Result = FirstValue ^ SecondValue;
+            State->Flags.Cf = State->Flags.Of = FALSE;
             break;
         }
 
@@ -209,7 +212,7 @@ Fast486RotateOperation(PFAST486_STATE State,
         case 2:
         {
             Result = (Value << Count) | (State->Flags.Cf << (Count - 1));
-            
+
             /* Complete the calculation, but make sure we don't shift by too much */
             if ((Bits - Count) < 31) Result |= Value >> (Bits - Count + 1);
 
@@ -491,10 +494,7 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroup8F)
 
     if (!Fast486ParseModRegRm(State, AddressSize, &ModRegRm))
     {
-        /* Exception occurred - restore SP */
-        if (OperandSize) State->GeneralRegs[FAST486_REG_ESP].Long -= sizeof(ULONG);
-        else State->GeneralRegs[FAST486_REG_ESP].LowWord -= sizeof(USHORT);
-
+        /* Exception occurred */
         return;
     }
 
@@ -993,7 +993,7 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF6)
             Quotient = State->GeneralRegs[FAST486_REG_EAX].LowWord / Value;
             Remainder = State->GeneralRegs[FAST486_REG_EAX].LowWord % Value;
 
-            if (Quotient > 0xFF) 
+            if (Quotient > 0xFF)
             {
                 /* Divide error */
                 Fast486Exception(State, FAST486_EXCEPTION_DE);
@@ -1023,7 +1023,7 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF6)
             Quotient = (SHORT)State->GeneralRegs[FAST486_REG_EAX].LowWord / (CHAR)Value;
             Remainder = (SHORT)State->GeneralRegs[FAST486_REG_EAX].LowWord % (CHAR)Value;
 
-            if (Quotient > 127 || Quotient < -128) 
+            if (Quotient > 127 || Quotient < -128)
             {
                 /* Divide error */
                 Fast486Exception(State, FAST486_EXCEPTION_DE);
@@ -1142,7 +1142,7 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroupF7)
         case 3:
         {
             /* Calculate the result */
-            ULONG Result = -Value;
+            ULONG Result = -(LONG)Value;
             if (!OperandSize) Result &= 0xFFFF;
 
             /* Update the flags */
@@ -1464,7 +1464,8 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFF)
                 return;
             }
 
-            if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
+            if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
+                && !State->Flags.Vm)
             {
                 if (!Fast486ProcessGate(State, Selector, Value, TRUE))
                 {
@@ -1526,7 +1527,8 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFF)
                 return;
             }
 
-            if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
+            if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
+                && !State->Flags.Vm)
             {
                 if (!Fast486ProcessGate(State, Selector, Value, FALSE))
                 {
@@ -1626,6 +1628,16 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFF)
                 return;
             }
 
+            if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
+                && !State->Flags.Vm)
+            {
+                if (!Fast486ProcessGate(State, Selector, Value, TRUE))
+                {
+                    /* Gate processed or exception occurred */
+                    return;
+                }
+            }
+
             /* Push the current value of CS */
             if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector))
             {
@@ -1685,6 +1697,16 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeGroupFF)
                 return;
             }
 
+            if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
+                && !State->Flags.Vm)
+            {
+                if (!Fast486ProcessGate(State, Selector, Value, FALSE))
+                {
+                    /* Gate processed or exception occurred */
+                    return;
+                }
+            }
+
             /* Load the new code segment */
             if (!Fast486LoadSegment(State, FAST486_REG_CS, Selector))
             {
@@ -1924,7 +1946,10 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F00)
                 return;
             }
 
-            if (GdtEntry.Signature != FAST486_TSS_SIGNATURE)
+            if (GdtEntry.Signature != FAST486_TSS_SIGNATURE
+                && GdtEntry.Signature != FAST486_BUSY_TSS_SIGNATURE
+                && GdtEntry.Signature != FAST486_TSS_16_SIGNATURE
+                && GdtEntry.Signature != FAST486_BUSY_TSS_16_SIGNATURE)
             {
                 /* This is not a TSS descriptor */
                 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
@@ -1942,6 +1967,19 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F00)
                 State->TaskReg.Limit |= 0x00000FFF;
             }
 
+            if (GdtEntry.Signature != FAST486_BUSY_TSS_SIGNATURE
+                && GdtEntry.Signature != FAST486_BUSY_TSS_16_SIGNATURE)
+            {
+                /* Set the busy bit of this TSS descriptor and write it back */
+                GdtEntry.Signature |= 2;
+
+                Fast486WriteLinearMemory(State,
+                                         State->Gdtr.Address + GET_SEGMENT_INDEX(Selector),
+                                         &GdtEntry,
+                                         sizeof(GdtEntry),
+                                         FALSE /* We already made sure CPL is 0 */);
+            }
+
             break;
         }
 
@@ -1961,13 +1999,6 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F00)
                 return;
             }
 
-            /* This is a privileged instruction */
-            if (Fast486GetCurrentPrivLevel(State) != 0)
-            {
-                Fast486Exception(State, FAST486_EXCEPTION_GP);
-                return;
-            }
-
             if (!Fast486ReadModrmWordOperands(State,
                                               &ModRegRm,
                                               NULL,
@@ -1992,23 +2023,23 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F00)
 
             /* Set ZF if it is valid and accessible */
             State->Flags.Zf = GdtEntry.Present // must be present
-                               && GdtEntry.SystemType // must be a segment
-                               && (((ModRegRm.Register == 4)
-                               /* code segments are only readable if the RW bit is set */
-                               && (!GdtEntry.Executable || GdtEntry.ReadWrite))
-                               || ((ModRegRm.Register == 5)
-                               /* code segments are never writable, data segments are writable when RW is set */
-                               && (!GdtEntry.Executable && GdtEntry.ReadWrite)))
-                               /*
-                                * for segments other than conforming code segments,
-                                * both RPL and CPL must be less than or equal to DPL
-                                */
-                               && ((!GdtEntry.Executable || !GdtEntry.DirConf)
-                               && ((GET_SEGMENT_RPL(Selector) <= GdtEntry.Dpl)
-                               && (Fast486GetCurrentPrivLevel(State) <= GdtEntry.Dpl)))
-                               /* for conforming code segments, DPL must be less than or equal to CPL */
-                               && ((GdtEntry.Executable && GdtEntry.DirConf)
-                               && (GdtEntry.Dpl <= Fast486GetCurrentPrivLevel(State)));
+                              && GdtEntry.SystemType // must be a segment
+                              && (((ModRegRm.Register == 4)
+                              /* code segments are only readable if the RW bit is set */
+                              && (!GdtEntry.Executable || GdtEntry.ReadWrite))
+                              || ((ModRegRm.Register == 5)
+                              /* code segments are never writable, data segments are writable when RW is set */
+                              && (!GdtEntry.Executable && GdtEntry.ReadWrite)))
+                              /*
+                               * for segments other than conforming code segments,
+                               * both RPL and CPL must be less than or equal to DPL
+                               */
+                              && (((!GdtEntry.Executable || !GdtEntry.DirConf)
+                              && (GET_SEGMENT_RPL(Selector) <= GdtEntry.Dpl)
+                              && (Fast486GetCurrentPrivLevel(State) <= GdtEntry.Dpl))
+                              /* for conforming code segments, DPL must be less than or equal to CPL */
+                              || ((GdtEntry.Executable && GdtEntry.DirConf)
+                              && (GdtEntry.Dpl <= Fast486GetCurrentPrivLevel(State))));
 
 
             break;
@@ -2199,11 +2230,14 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F01)
         {
             USHORT MachineStatusWord;
 
-            /* This is a privileged instruction */
-            if (Fast486GetCurrentPrivLevel(State) != 0)
+            if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
             {
-                Fast486Exception(State, FAST486_EXCEPTION_GP);
-                return;
+                /* This is a privileged instruction */
+                if (Fast486GetCurrentPrivLevel(State) != 0)
+                {
+                    Fast486Exception(State, FAST486_EXCEPTION_GP);
+                    return;
+                }
             }
 
             /* Read the new Machine Status Word */
@@ -2213,16 +2247,8 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F01)
                 return;
             }
 
-            /* This instruction cannot be used to return to real mode */
-            if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
-                && !(MachineStatusWord & FAST486_CR0_PE))
-            {
-                Fast486Exception(State, FAST486_EXCEPTION_GP);
-                return;
-            }
-
-            /* Set the lowest 4 bits */
-            State->ControlRegisters[FAST486_REG_CR0] &= 0xFFFFFFF0;
+            /* Set the lowest 4 bits, but never clear bit 0 */
+            State->ControlRegisters[FAST486_REG_CR0] &= 0xFFFFFFF1;
             State->ControlRegisters[FAST486_REG_CR0] |= MachineStatusWord & 0x0F;
 
             break;