[FAST486]
authorAleksandar Andrejevic <aandrejevic@reactos.org>
Thu, 6 Nov 2014 05:16:14 +0000 (05:16 +0000)
committerAleksandar Andrejevic <aandrejevic@reactos.org>
Thu, 6 Nov 2014 05:16:14 +0000 (05:16 +0000)
Fix the limit calculation when using page granularity.
RETF can also perform inter-privilege returns.
Fix the privilege checks when loading CS. DPL != CPL is only a #GP
when we're doing a jump or a call.

svn path=/trunk/; revision=65280

reactos/lib/fast486/common.c
reactos/lib/fast486/common.inl
reactos/lib/fast486/extraops.c
reactos/lib/fast486/opcodes.c
reactos/lib/fast486/opgroups.c

index 3d666ae..a16b591 100644 (file)
@@ -553,7 +553,12 @@ Fast486TaskSwitch(PFAST486_STATE State, FAST486_TASK_SWITCH_TYPE Type, USHORT Se
 
     /* Calculate the limit of the new TSS */
     NewTssLimit = NewTssDescriptor.Limit | (NewTssDescriptor.LimitHigh << 16);
-    if (NewTssDescriptor.Granularity) NewTssLimit <<= 12;
+
+    if (NewTssDescriptor.Granularity)
+    {
+        NewTssLimit <<= 12;
+        NewTssLimit |= 0x00000FFF;
+    }
 
     if (NewTssLimit < sizeof(FAST486_TSS))
     {
@@ -739,7 +744,12 @@ Fast486TaskSwitch(PFAST486_STATE State, FAST486_TASK_SWITCH_TYPE Type, USHORT Se
         State->Ldtr.Selector = NewTss.Ldtr;
         State->Ldtr.Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24);
         State->Ldtr.Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
-        if (GdtEntry.Granularity) State->Ldtr.Limit <<= 12;
+
+        if (GdtEntry.Granularity)
+        {
+            State->Ldtr.Limit <<= 12;
+            State->Ldtr.Limit |= 0x00000FFF;
+        }
     }
     else
     {
index 6828583..73bb537 100644 (file)
@@ -594,16 +594,12 @@ Fast486LoadSegmentInternal(PFAST486_STATE State,
             {
                 /* Regular code segment */
 
-                if ((GET_SEGMENT_RPL(Selector) > Fast486GetCurrentPrivLevel(State))
-                    || (Fast486GetCurrentPrivLevel(State) != GdtEntry.Dpl))
+                if ((GET_SEGMENT_RPL(Selector) < Fast486GetCurrentPrivLevel(State)))
                 {
                     Fast486ExceptionWithErrorCode(State, Exception, Selector);
                     return FALSE;
                 }
             }
-
-            /* Update CPL */
-            State->Cpl = GET_SEGMENT_RPL(Selector);
         }
         else
         {
@@ -653,7 +649,11 @@ Fast486LoadSegmentInternal(PFAST486_STATE State,
         CachedDescriptor->Size = GdtEntry.Size;
 
         /* Check for page granularity */
-        if (GdtEntry.Granularity) CachedDescriptor->Limit <<= 12;
+        if (GdtEntry.Granularity)
+        {
+            CachedDescriptor->Limit <<= 12;
+            CachedDescriptor->Limit |= 0x00000FFF;
+        }
     }
     else
     {
@@ -730,6 +730,13 @@ Fast486ProcessGate(PFAST486_STATE State, USHORT Selector, ULONG Offset, BOOLEAN
 
         default:
         {
+            /* Security check for jumps and calls only */
+            if (State->Cpl != Descriptor.Dpl)
+            {
+                Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
+                return FALSE;
+            }
+
             return TRUE;
         }
     }
index 6a73fb8..1f2fc72 100644 (file)
@@ -475,7 +475,12 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLsl)
 
     /* Calculate the limit */
     Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
-    if (GdtEntry.Granularity) Limit <<= 12;
+
+    if (GdtEntry.Granularity)
+    {
+        Limit <<= 12;
+        Limit |= 0x00000FFF;
+    }
 
     /* Set ZF */
     State->Flags.Zf = TRUE;
index 0e004ea..7ac8014 100644 (file)
@@ -4474,6 +4474,63 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeRetFar)
         return;
     }
 
+    if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) && !State->Flags.Vm)
+    {
+        INT i;
+        INT 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;
+            }
+
+            /* 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);
+        }
+
+        /* Update the CPL */
+        State->Cpl = GET_SEGMENT_RPL(Segment);
+
+        if (State->Cpl > OldCpl)
+        {
+            /* 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)
     {
@@ -4582,7 +4639,7 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeIret)
     /* Check for protected mode */
     if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
     {
-        INT Cpl = Fast486GetCurrentPrivLevel(State);
+        INT OldCpl = Fast486GetCurrentPrivLevel(State);
 
         if (State->Flags.Vm)
         {
@@ -4660,7 +4717,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))
@@ -4688,27 +4745,27 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeIret)
             else State->GeneralRegs[FAST486_REG_ESP].LowWord = LOWORD(StackPtr);
         }
 
+        /* 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 (Cpl <= State->Flags.Iopl) State->Flags.If = NewFlags.If;
-        if (Cpl == 0) State->Flags.Iopl = NewFlags.Iopl;
+        if (OldCpl <= State->Flags.Iopl) State->Flags.If = NewFlags.If;
+        if (OldCpl == 0) State->Flags.Iopl = NewFlags.Iopl;
 
-        if (GET_SEGMENT_RPL(CodeSel) > Cpl)
+        if (State->Cpl > OldCpl)
         {
-            /* Update the CPL */
-            Cpl = Fast486GetCurrentPrivLevel(State);
-
             /* 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 ((Cpl > State->SegmentRegs[i].Dpl)
+                if ((State->Cpl > State->SegmentRegs[i].Dpl)
                     && (!State->SegmentRegs[i].Executable
                     || !State->SegmentRegs[i].DirConf))
                 {
index 95a99cc..3f5e828 100644 (file)
@@ -1804,7 +1804,12 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F00)
             State->Ldtr.Selector = Selector;
             State->Ldtr.Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24);
             State->Ldtr.Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
-            if (GdtEntry.Granularity) State->Ldtr.Limit <<= 12;
+
+            if (GdtEntry.Granularity)
+            {
+                State->Ldtr.Limit <<= 12;
+                State->Ldtr.Limit |= 0x00000FFF;
+            }
 
             break;
         }
@@ -1886,7 +1891,12 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F00)
             State->TaskReg.Selector = Selector;
             State->TaskReg.Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24);
             State->TaskReg.Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
-            if (GdtEntry.Granularity) State->TaskReg.Limit <<= 12;
+
+            if (GdtEntry.Granularity)
+            {
+                State->TaskReg.Limit <<= 12;
+                State->TaskReg.Limit |= 0x00000FFF;
+            }
 
             break;
         }