Sync with trunk r63502.
[reactos.git] / lib / fast486 / common.inl
index cbced3a..a558ed4 100644 (file)
@@ -122,13 +122,13 @@ Fast486ReadLinearMemory(PFAST486_STATE State,
                         PVOID Buffer,
                         ULONG Size)
 {
-    INT Cpl = Fast486GetCurrentPrivLevel(State);
-
     /* Check if paging is enabled */
     if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PG)
     {
         ULONG Page;
         FAST486_PAGE_TABLE TableEntry;
+        INT Cpl = Fast486GetCurrentPrivLevel(State);
+        ULONG BufferOffset = 0;
 
         for (Page = PAGE_ALIGN(LinearAddress);
              Page <= PAGE_ALIGN(LinearAddress + Size - 1);
@@ -151,22 +151,25 @@ Fast486ReadLinearMemory(PFAST486_STATE State,
             /* Check if this is the first page */
             if (Page == PAGE_ALIGN(LinearAddress))
             {
-                /* Start copying from the offset from the beginning of the page */
+                /* Start reading from the offset from the beginning of the page */
                 PageOffset = PAGE_OFFSET(LinearAddress);
+                PageLength -= PageOffset;
             }
 
             /* Check if this is the last page */
             if (Page == PAGE_ALIGN(LinearAddress + Size - 1))
             {
-                /* Copy only a part of the page */
-                PageLength = PAGE_OFFSET(LinearAddress + Size);
+                /* Read only a part of the page */
+                PageLength = PAGE_OFFSET(LinearAddress + Size - 1) - PageOffset + 1;
             }
 
             /* Read the memory */
             State->MemReadCallback(State,
                                    (TableEntry.Address << 12) | PageOffset,
-                                   Buffer,
+                                   (PVOID)((ULONG_PTR)Buffer + BufferOffset),
                                    PageLength);
+
+            BufferOffset += PageLength;
         }
     }
     else
@@ -185,13 +188,13 @@ Fast486WriteLinearMemory(PFAST486_STATE State,
                          PVOID Buffer,
                          ULONG Size)
 {
-    INT Cpl = Fast486GetCurrentPrivLevel(State);
-
     /* Check if paging is enabled */
     if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PG)
     {
         ULONG Page;
         FAST486_PAGE_TABLE TableEntry;
+        INT Cpl = Fast486GetCurrentPrivLevel(State);
+        ULONG BufferOffset = 0;
 
         for (Page = PAGE_ALIGN(LinearAddress);
              Page <= PAGE_ALIGN(LinearAddress + Size - 1);
@@ -216,22 +219,25 @@ Fast486WriteLinearMemory(PFAST486_STATE State,
             /* Check if this is the first page */
             if (Page == PAGE_ALIGN(LinearAddress))
             {
-                /* Start copying from the offset from the beginning of the page */
+                /* Start writing from the offset from the beginning of the page */
                 PageOffset = PAGE_OFFSET(LinearAddress);
+                PageLength -= PageOffset;
             }
 
             /* Check if this is the last page */
             if (Page == PAGE_ALIGN(LinearAddress + Size - 1))
             {
-                /* Copy only a part of the page */
-                PageLength = PAGE_OFFSET(LinearAddress + Size);
+                /* Write only a part of the page */
+                PageLength = PAGE_OFFSET(LinearAddress + Size - 1) - PageOffset + 1;
             }
 
             /* Write the memory */
             State->MemWriteCallback(State,
                                     (TableEntry.Address << 12) | PageOffset,
-                                    Buffer,
+                                    (PVOID)((ULONG_PTR)Buffer + BufferOffset),
                                     PageLength);
+
+            BufferOffset += PageLength;
         }
     }
     else
@@ -275,7 +281,7 @@ Fast486StackPush(PFAST486_STATE State,
         }
 
         /* Subtract ESP by 4 */
-        State->GeneralRegs[FAST486_REG_ESP].Long -= 4;
+        State->GeneralRegs[FAST486_REG_ESP].Long -= sizeof(ULONG);
 
         /* Store the value in SS:ESP */
         return Fast486WriteMemory(State,
@@ -290,14 +296,14 @@ Fast486StackPush(PFAST486_STATE State,
         USHORT ShortValue = LOWORD(Value);
 
         /* Check if SP is 1 */
-        if (State->GeneralRegs[FAST486_REG_ESP].Long == 1)
+        if (State->GeneralRegs[FAST486_REG_ESP].LowWord == 1)
         {
             Fast486Exception(State, FAST486_EXCEPTION_SS);
             return FALSE;
         }
 
         /* Subtract SP by 2 */
-        State->GeneralRegs[FAST486_REG_ESP].LowWord -= 2;
+        State->GeneralRegs[FAST486_REG_ESP].LowWord -= sizeof(USHORT);
 
         /* Store the value in SS:SP */
         return Fast486WriteMemory(State,
@@ -313,8 +319,6 @@ BOOLEAN
 Fast486StackPop(PFAST486_STATE State,
                 PULONG Value)
 {
-    ULONG LongValue;
-    USHORT ShortValue;
     BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size;
 
     /* The OPSIZE prefix toggles the size */
@@ -323,6 +327,7 @@ Fast486StackPop(PFAST486_STATE State,
     if (Size)
     {
         /* 32-bit size */
+        ULONG LongValue;
 
         /* Check if ESP is 0xFFFFFFFF */
         if (State->GeneralRegs[FAST486_REG_ESP].Long == 0xFFFFFFFF)
@@ -344,7 +349,7 @@ Fast486StackPop(PFAST486_STATE State,
         }
 
         /* Increment ESP by 4 */
-        State->GeneralRegs[FAST486_REG_ESP].Long += 4;
+        State->GeneralRegs[FAST486_REG_ESP].Long += sizeof(ULONG);
 
         /* Store the value in the result */
         *Value = LongValue;
@@ -352,6 +357,7 @@ Fast486StackPop(PFAST486_STATE State,
     else
     {
         /* 16-bit size */
+        USHORT ShortValue;
 
         /* Check if SP is 0xFFFF */
         if (State->GeneralRegs[FAST486_REG_ESP].LowWord == 0xFFFF)
@@ -373,7 +379,7 @@ Fast486StackPop(PFAST486_STATE State,
         }
 
         /* Increment SP by 2 */
-        State->GeneralRegs[FAST486_REG_ESP].LowWord += 2;
+        State->GeneralRegs[FAST486_REG_ESP].LowWord += sizeof(USHORT);
 
         /* Store the value in the result */
         *Value = ShortValue;
@@ -385,7 +391,7 @@ Fast486StackPop(PFAST486_STATE State,
 FORCEINLINE
 BOOLEAN
 Fast486LoadSegment(PFAST486_STATE State,
-                   INT Segment,
+                   FAST486_SEG_REGS Segment,
                    USHORT Selector)
 {
     PFAST486_SEG_REG CachedDescriptor;
@@ -399,22 +405,45 @@ Fast486LoadSegment(PFAST486_STATE State,
     /* Check for protected mode */
     if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) && !State->Flags.Vm)
     {
-        /* Make sure the GDT contains the entry */
-        if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1))
+        if (!(Selector & SEGMENT_TABLE_INDICATOR))
         {
-            Fast486Exception(State, FAST486_EXCEPTION_GP);
-            return FALSE;
-        }
+            /* Make sure the GDT contains the entry */
+            if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1))
+            {
+                Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
+                return FALSE;
+            }
 
-        /* Read the GDT */
-        if (!Fast486ReadLinearMemory(State,
-                                     State->Gdtr.Address
-                                     + GET_SEGMENT_INDEX(Selector),
-                                     &GdtEntry,
-                                     sizeof(GdtEntry)))
+            /* Read the GDT */
+            if (!Fast486ReadLinearMemory(State,
+                                         State->Gdtr.Address
+                                         + GET_SEGMENT_INDEX(Selector),
+                                         &GdtEntry,
+                                         sizeof(GdtEntry)))
+            {
+                /* Exception occurred */
+                return FALSE;
+            }
+        }
+        else
         {
-            /* Exception occurred */
-            return FALSE;
+            /* Make sure the LDT contains the entry */
+            if (GET_SEGMENT_INDEX(Selector) >= (State->Ldtr.Limit + 1))
+            {
+                Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
+                return FALSE;
+            }
+
+            /* Read the LDT */
+            if (!Fast486ReadLinearMemory(State,
+                                         State->Ldtr.Base
+                                         + GET_SEGMENT_INDEX(Selector),
+                                         &GdtEntry,
+                                         sizeof(GdtEntry)))
+            {
+                /* Exception occurred */
+                return FALSE;
+            }
         }
 
         if (Segment == FAST486_REG_SS)
@@ -430,59 +459,115 @@ Fast486LoadSegment(PFAST486_STATE State,
             if (!GdtEntry.SystemType)
             {
                 /* This is a special descriptor */
-                Fast486Exception(State, FAST486_EXCEPTION_GP);
+                Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
                 return FALSE;
             }
 
             if (GdtEntry.Executable || !GdtEntry.ReadWrite)
             {
-                Fast486Exception(State, FAST486_EXCEPTION_GP);
+                Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
                 return FALSE;
             }
 
             if ((GET_SEGMENT_RPL(Selector) != Fast486GetCurrentPrivLevel(State))
                 || (GET_SEGMENT_RPL(Selector) != GdtEntry.Dpl))
             {
-                Fast486Exception(State, FAST486_EXCEPTION_GP);
+                Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
                 return FALSE;
             }
 
             if (!GdtEntry.Present)
             {
-                Fast486Exception(State, FAST486_EXCEPTION_SS);
+                Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_SS, Selector);
                 return FALSE;
             }
         }
         else if (Segment == FAST486_REG_CS)
         {
             /* Loading the code segment */
-            // TODO: Implement security checks, call gates, etc...
 
-            /* Update CPL */
-            State->Cpl = GET_SEGMENT_RPL(Selector);
-        }
-        else
-        {
-            /* Loading a data segment */
-
-            if (!GdtEntry.SystemType)
+            if (GET_SEGMENT_INDEX(Selector) == 0)
             {
-                /* This is a special descriptor */
                 Fast486Exception(State, FAST486_EXCEPTION_GP);
                 return FALSE;
             }
 
-            if ((GET_SEGMENT_RPL(Selector) > GdtEntry.Dpl)
-                || (Fast486GetCurrentPrivLevel(State) > GdtEntry.Dpl))
+            if (!GdtEntry.SystemType)
             {
-                Fast486Exception(State, FAST486_EXCEPTION_GP);
-                return FALSE;
+                // TODO: Call/interrupt/task gates NOT IMPLEMENTED!
+                UNIMPLEMENTED;
             }
+            else
+            {
+                if (!GdtEntry.Present)
+                {
+                    Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
+                    return FALSE;
+                }
 
-            if (!GdtEntry.Present)
+                if (!GdtEntry.Executable)
+                {
+                    Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
+                    return FALSE;
+                }
+
+                if (GdtEntry.DirConf)
+                {
+                    /* Conforming Code Segment */
+
+                    if (GdtEntry.Dpl > Fast486GetCurrentPrivLevel(State))
+                    {
+                        /* Must be accessed from lower-privileged code */
+                        Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
+                        return FALSE;
+                    }
+                }
+                else
+                {
+                    /* Regular code segment */
+
+                    if ((GET_SEGMENT_RPL(Selector) > Fast486GetCurrentPrivLevel(State))
+                        || (Fast486GetCurrentPrivLevel(State) != GdtEntry.Dpl))
+                    {
+                        Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
+                        return FALSE;
+                    }
+                }
+
+                /* Update CPL */
+                State->Cpl = GET_SEGMENT_RPL(Selector);
+            }
+        }
+        else
+        {
+            /* Loading a data segment */
+
+            if (GET_SEGMENT_INDEX(Selector) != 0)
             {
-                Fast486Exception(State, FAST486_EXCEPTION_NP);
-                return FALSE;
+                if (!GdtEntry.SystemType)
+                {
+                    /* This is a special descriptor */
+                    Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
+                    return FALSE;
+                }
+
+                if ((GET_SEGMENT_RPL(Selector) > GdtEntry.Dpl)
+                    || (Fast486GetCurrentPrivLevel(State) > GdtEntry.Dpl))
+                {
+                    Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
+                    return FALSE;
+                }
+
+                if (!GdtEntry.Present)
+                {
+                    Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
+                    return FALSE;
+                }
+            }
+            else
+            {
+                /* This is a NULL selector */
+                RtlZeroMemory(&GdtEntry, sizeof(GdtEntry));
             }
         }
 
@@ -495,6 +580,7 @@ Fast486LoadSegment(PFAST486_STATE State,
         CachedDescriptor->DirConf = GdtEntry.DirConf;
         CachedDescriptor->Executable = GdtEntry.Executable;
         CachedDescriptor->SystemType = GdtEntry.SystemType;
+        CachedDescriptor->Rpl = GET_SEGMENT_RPL(Selector);
         CachedDescriptor->Dpl = GdtEntry.Dpl;
         CachedDescriptor->Present = GdtEntry.Present;
         CachedDescriptor->Size = GdtEntry.Size;