[FAST486]
authorAleksandar Andrejevic <aandrejevic@reactos.org>
Sun, 10 Nov 2013 22:27:24 +0000 (22:27 +0000)
committerAleksandar Andrejevic <aandrejevic@reactos.org>
Sun, 10 Nov 2013 22:27:24 +0000 (22:27 +0000)
Modularize linear memory access by adding two new functions:
Fast486ReadLinearMemory and Fast486WriteLinearMemory.
Implement Fast486GetPageTableEntry.

svn path=/branches/ntvdm/; revision=60923

include/reactos/libs/fast486/fast486.h
lib/fast486/common.c
lib/fast486/common.h
lib/fast486/common.inl
lib/fast486/fast486.c
subsystems/ntvdm/emulator.c

index df03b80..2a2a563 100644 (file)
@@ -401,6 +401,7 @@ struct _FAST486_STATE
     FAST486_SEG_REGS SegmentOverride;
     FAST486_INT_STATUS IntStatus;
     UCHAR PendingIntNum;
+    PULONG Tlb;
 };
 
 /* FUNCTIONS ******************************************************************/
@@ -414,7 +415,8 @@ Fast486Initialize(PFAST486_STATE         State,
                   FAST486_IO_WRITE_PROC  IoWriteCallback,
                   FAST486_IDLE_PROC      IdleCallback,
                   FAST486_BOP_PROC       BopCallback,
-                  FAST486_INT_ACK_PROC   IntAckCallback);
+                  FAST486_INT_ACK_PROC   IntAckCallback,
+                  PULONG                 Tlb);
 
 VOID
 NTAPI
index 4753fef..871d77d 100644 (file)
 #include <fast486.h>
 #include "common.h"
 
-/* PRIVATE FUNCTIONS **********************************************************/
-
-static inline
-ULONG
-Fast486GetPageTableEntry(PFAST486_STATE State,
-                         ULONG VirtualAddress)
-{
-    // TODO: NOT IMPLEMENTED
-    UNIMPLEMENTED;
-
-    return 0;
-}
-
 /* PUBLIC FUNCTIONS ***********************************************************/
 
 BOOLEAN
@@ -54,7 +41,6 @@ Fast486ReadMemory(PFAST486_STATE State,
 {
     ULONG LinearAddress;
     PFAST486_SEG_REG CachedDescriptor;
-    INT Cpl = Fast486GetCurrentPrivLevel(State);
 
     ASSERT(SegmentReg < FAST486_NUM_SEG_REGS);
 
@@ -108,58 +94,8 @@ Fast486ReadMemory(PFAST486_STATE State,
     /* Find the linear address */
     LinearAddress = CachedDescriptor->Base + Offset;
 
-    /* Check if paging is enabled */
-    if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PG)
-    {
-        ULONG Page;
-        FAST486_PAGE_TABLE TableEntry;
-
-        for (Page = PAGE_ALIGN(LinearAddress);
-             Page <= PAGE_ALIGN(LinearAddress + Size - 1);
-             Page += PAGE_SIZE)
-        {
-            ULONG PageOffset = 0, PageLength = PAGE_SIZE;
-
-            /* Get the table entry */
-            TableEntry.Value = Fast486GetPageTableEntry(State, Page);
-
-            if (!TableEntry.Present || (!TableEntry.Usermode && (Cpl > 0)))
-            {
-                /* Exception */
-                Fast486ExceptionWithErrorCode(State,
-                                              FAST486_EXCEPTION_PF,
-                                              TableEntry.Value & 0x07);
-                return FALSE;
-            }
-
-            /* Check if this is the first page */
-            if (Page == PAGE_ALIGN(LinearAddress))
-            {
-                /* Start copying from the offset from the beginning of the page */
-                PageOffset = PAGE_OFFSET(LinearAddress);
-            }
-
-            /* 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 the memory */
-            State->MemReadCallback(State,
-                                   (TableEntry.Address << 12) | PageOffset,
-                                   Buffer,
-                                   PageLength);
-        }
-    }
-    else
-    {
-        /* Read the memory */
-        State->MemReadCallback(State, LinearAddress, Buffer, Size);
-    }
-
-    return TRUE;
+    /* Read from the linear address */
+    return Fast486ReadLinearMemory(State, LinearAddress, Buffer, Size);
 }
 
 BOOLEAN
@@ -171,7 +107,6 @@ Fast486WriteMemory(PFAST486_STATE State,
 {
     ULONG LinearAddress;
     PFAST486_SEG_REG CachedDescriptor;
-    INT Cpl = Fast486GetCurrentPrivLevel(State);
 
     ASSERT(SegmentReg < FAST486_NUM_SEG_REGS);
 
@@ -220,60 +155,8 @@ Fast486WriteMemory(PFAST486_STATE State,
     /* Find the linear address */
     LinearAddress = CachedDescriptor->Base + Offset;
 
-    /* Check if paging is enabled */
-    if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PG)
-    {
-        ULONG Page;
-        FAST486_PAGE_TABLE TableEntry;
-
-        for (Page = PAGE_ALIGN(LinearAddress);
-             Page <= PAGE_ALIGN(LinearAddress + Size - 1);
-             Page += PAGE_SIZE)
-        {
-            ULONG PageOffset = 0, PageLength = PAGE_SIZE;
-
-            /* Get the table entry */
-            TableEntry.Value = Fast486GetPageTableEntry(State, Page);
-
-            if ((!TableEntry.Present || (!TableEntry.Usermode && (Cpl > 0)))
-                || ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_WP)
-                && !TableEntry.Writeable))
-            {
-                /* Exception */
-                Fast486ExceptionWithErrorCode(State,
-                                              FAST486_EXCEPTION_PF,
-                                              TableEntry.Value & 0x07);
-                return FALSE;
-            }
-
-            /* Check if this is the first page */
-            if (Page == PAGE_ALIGN(LinearAddress))
-            {
-                /* Start copying from the offset from the beginning of the page */
-                PageOffset = PAGE_OFFSET(LinearAddress);
-            }
-
-            /* 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 the memory */
-            State->MemWriteCallback(State,
-                                    (TableEntry.Address << 12) | PageOffset,
-                                    Buffer,
-                                    PageLength);
-        }
-    }
-    else
-    {
-        /* Write the memory */
-        State->MemWriteCallback(State, LinearAddress, Buffer, Size);
-    }
-
-    return TRUE;
+    /* Write to the linear address */
+    return Fast486WriteLinearMemory(State, LinearAddress, Buffer, Size);
 }
 
 BOOLEAN
@@ -293,11 +176,14 @@ Fast486InterruptInternal(PFAST486_STATE State,
         if (Fast486GetCurrentPrivLevel(State) > GET_SEGMENT_RPL(SegmentSelector))
         {
             /* Read the TSS */
-            // FIXME: This code is only correct when paging is disabled!!!
-            State->MemReadCallback(State,
-                                   State->Tss.Address,
-                                   &Tss,
-                                   sizeof(Tss));
+            if (!Fast486ReadLinearMemory(State,
+                                         State->Tss.Address,
+                                         &Tss,
+                                         sizeof(Tss)))
+            {
+                /* Exception occurred */
+                return FALSE;
+            }
 
             /* Check the new (higher) privilege level */
             switch (GET_SEGMENT_RPL(SegmentSelector))
index 8bb8d02..39c629d 100644 (file)
@@ -56,6 +56,9 @@
 
 #define PAGE_ALIGN(x)   ((x) & 0xFFFFF000)
 #define PAGE_OFFSET(x)  ((x) & 0x00000FFF)
+#define GET_ADDR_PDE(x) ((x) >> 22)
+#define GET_ADDR_PTE(x) (((x) >> 12) & 0x3FF)
+#define INVALID_TLB_FIELD 0xFFFFFFFF
 
 #ifndef PAGE_SIZE
 #define PAGE_SIZE   4096
@@ -92,6 +95,8 @@ typedef union _FAST486_PAGE_DIR
     ULONG Value;
 } FAST486_PAGE_DIR, *PFAST486_PAGE_DIR;
 
+C_ASSERT(sizeof(FAST486_PAGE_DIR) == sizeof(ULONG));
+
 typedef union _FAST486_PAGE_TABLE
 {
     struct
@@ -111,6 +116,8 @@ typedef union _FAST486_PAGE_TABLE
     ULONG Value;
 } FAST486_PAGE_TABLE, *PFAST486_PAGE_TABLE;
 
+C_ASSERT(sizeof(FAST486_PAGE_DIR) == sizeof(ULONG));
+
 #pragma pack(pop)
 
 /* FUNCTIONS ******************************************************************/
index 9cadacb..4d8fdb2 100644 (file)
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 
+#include "common.h"
+
 /* PUBLIC FUNCTIONS ***********************************************************/
 
+FORCEINLINE
+ULONG
+Fast486GetPageTableEntry(PFAST486_STATE State,
+                         ULONG VirtualAddress,
+                         BOOLEAN MarkAsDirty)
+{
+    ULONG PdeIndex = GET_ADDR_PDE(VirtualAddress);
+    ULONG PteIndex = GET_ADDR_PTE(VirtualAddress);
+    FAST486_PAGE_DIR DirectoryEntry;
+    FAST486_PAGE_TABLE TableEntry;
+    ULONG PageDirectory = State->ControlRegisters[FAST486_REG_CR3];
+
+    if ((State->Tlb != NULL)
+        && (State->Tlb[VirtualAddress >> 12] != INVALID_TLB_FIELD))
+    {
+        /* Return the cached entry */
+        return State->Tlb[VirtualAddress >> 12];
+    }
+
+    /* Read the directory entry */
+    State->MemReadCallback(State,
+                           PageDirectory + PdeIndex * sizeof(ULONG),
+                           &DirectoryEntry.Value,
+                           sizeof(DirectoryEntry));
+
+    /* Make sure it is present */
+    if (!DirectoryEntry.Present) return 0;
+
+    /* Was the directory entry accessed before? */
+    if (!DirectoryEntry.Accessed)
+    {
+        /* Well, it is now */
+        DirectoryEntry.Accessed = TRUE;
+
+        /* Write back the directory entry */
+        State->MemWriteCallback(State,
+                                PageDirectory + PdeIndex * sizeof(ULONG),
+                                &DirectoryEntry.Value,
+                                sizeof(DirectoryEntry));
+    }
+
+    /* Read the table entry */
+    State->MemReadCallback(State,
+                           (DirectoryEntry.TableAddress << 12)
+                           + PteIndex * sizeof(ULONG),
+                           &TableEntry.Value,
+                           sizeof(TableEntry));
+
+    /* Make sure it is present */
+    if (!TableEntry.Present) return 0;
+
+    if (MarkAsDirty) TableEntry.Dirty = TRUE;
+
+    /* Was the table entry accessed before? */
+    if (!TableEntry.Accessed)
+    {
+        /* Well, it is now */
+        TableEntry.Accessed = TRUE;
+
+        /* Write back the table entry */
+        State->MemWriteCallback(State,
+                                (DirectoryEntry.TableAddress << 12)
+                                + PteIndex * sizeof(ULONG),
+                                &TableEntry.Value,
+                                sizeof(TableEntry));
+    }
+
+    /*
+     * The resulting permissions depend on the permissions
+     * in the page directory table too
+     */
+    TableEntry.Writeable &= DirectoryEntry.Writeable;
+    TableEntry.Usermode &= DirectoryEntry.Usermode;
+
+    if (State->Tlb != NULL)
+    {
+        /* Set the TLB entry */
+        State->Tlb[VirtualAddress >> 12] = TableEntry.Value;
+    }
+
+    /* Return the table entry */
+    return TableEntry.Value;
+}
+
+FORCEINLINE
+BOOLEAN
+Fast486ReadLinearMemory(PFAST486_STATE State,
+                        ULONG LinearAddress,
+                        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;
+
+        for (Page = PAGE_ALIGN(LinearAddress);
+             Page <= PAGE_ALIGN(LinearAddress + Size - 1);
+             Page += PAGE_SIZE)
+        {
+            ULONG PageOffset = 0, PageLength = PAGE_SIZE;
+
+            /* Get the table entry */
+            TableEntry.Value = Fast486GetPageTableEntry(State, Page, FALSE);
+
+            if (!TableEntry.Present || (!TableEntry.Usermode && (Cpl > 0)))
+            {
+                /* Exception */
+                Fast486ExceptionWithErrorCode(State,
+                                              FAST486_EXCEPTION_PF,
+                                              TableEntry.Value & 0x07);
+                return FALSE;
+            }
+
+            /* Check if this is the first page */
+            if (Page == PAGE_ALIGN(LinearAddress))
+            {
+                /* Start copying from the offset from the beginning of the page */
+                PageOffset = PAGE_OFFSET(LinearAddress);
+            }
+
+            /* 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 the memory */
+            State->MemReadCallback(State,
+                                   (TableEntry.Address << 12) | PageOffset,
+                                   Buffer,
+                                   PageLength);
+        }
+    }
+    else
+    {
+        /* Read the memory */
+        State->MemReadCallback(State, LinearAddress, Buffer, Size);
+    }
+
+    return TRUE;
+}
+
+FORCEINLINE
+BOOLEAN
+Fast486WriteLinearMemory(PFAST486_STATE State,
+                         ULONG LinearAddress,
+                         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;
+
+        for (Page = PAGE_ALIGN(LinearAddress);
+             Page <= PAGE_ALIGN(LinearAddress + Size - 1);
+             Page += PAGE_SIZE)
+        {
+            ULONG PageOffset = 0, PageLength = PAGE_SIZE;
+
+            /* Get the table entry */
+            TableEntry.Value = Fast486GetPageTableEntry(State, Page, TRUE);
+
+            if ((!TableEntry.Present || (!TableEntry.Usermode && (Cpl > 0)))
+                || ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_WP)
+                && !TableEntry.Writeable))
+            {
+                /* Exception */
+                Fast486ExceptionWithErrorCode(State,
+                                              FAST486_EXCEPTION_PF,
+                                              TableEntry.Value & 0x07);
+                return FALSE;
+            }
+
+            /* Check if this is the first page */
+            if (Page == PAGE_ALIGN(LinearAddress))
+            {
+                /* Start copying from the offset from the beginning of the page */
+                PageOffset = PAGE_OFFSET(LinearAddress);
+            }
+
+            /* 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 the memory */
+            State->MemWriteCallback(State,
+                                    (TableEntry.Address << 12) | PageOffset,
+                                    Buffer,
+                                    PageLength);
+        }
+    }
+    else
+    {
+        /* Write the memory */
+        State->MemWriteCallback(State, LinearAddress, Buffer, Size);
+    }
+
+    return TRUE;
+}
+
 FORCEINLINE
 VOID
 Fast486Exception(PFAST486_STATE State,
@@ -185,12 +399,15 @@ Fast486LoadSegment(PFAST486_STATE State,
         }
 
         /* Read the GDT */
-        // FIXME: This code is only correct when paging is disabled!!!
-        State->MemReadCallback(State,
-                               State->Gdtr.Address
-                               + GET_SEGMENT_INDEX(Selector),
-                               &GdtEntry,
-                               sizeof(GdtEntry));
+        if (!Fast486ReadLinearMemory(State,
+                                     State->Gdtr.Address
+                                     + GET_SEGMENT_INDEX(Selector),
+                                     &GdtEntry,
+                                     sizeof(GdtEntry)))
+        {
+            /* Exception occurred */
+            return FALSE;
+        }
 
         if (Segment == FAST486_REG_SS)
         {
@@ -388,12 +605,15 @@ Fast486GetIntVector(PFAST486_STATE State,
     if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
     {
         /* Read from the IDT */
-        // FIXME: This code is only correct when paging is disabled!!!
-        State->MemReadCallback(State,
-                               State->Idtr.Address
-                               + Number * sizeof(*IdtEntry),
-                               IdtEntry,
-                               sizeof(*IdtEntry));
+        if (!Fast486ReadLinearMemory(State,
+                                     State->Idtr.Address
+                                     + Number * sizeof(*IdtEntry),
+                                     IdtEntry,
+                                     sizeof(*IdtEntry)))
+        {
+            /* Exception occurred */
+            return FALSE;
+        }
     }
     else
     {
@@ -417,10 +637,6 @@ Fast486GetIntVector(PFAST486_STATE State,
         IdtEntry->OffsetHigh = 0;
     }
 
-    /*
-     * Once paging support is implemented this function
-     * will not always return true
-     */
     return TRUE;
 }
 
index 05ee559..ac08829 100644 (file)
@@ -203,7 +203,8 @@ Fast486Initialize(PFAST486_STATE         State,
                   FAST486_IO_WRITE_PROC  IoWriteCallback,
                   FAST486_IDLE_PROC      IdleCallback,
                   FAST486_BOP_PROC       BopCallback,
-                  FAST486_INT_ACK_PROC   IntAckCallback)
+                  FAST486_INT_ACK_PROC   IntAckCallback,
+                  PULONG                 Tlb)
 {
     /* Set the callbacks (or use default ones if some are NULL) */
     State->MemReadCallback  = (MemReadCallback  ? MemReadCallback  : Fast486MemReadCallback );
@@ -214,6 +215,9 @@ Fast486Initialize(PFAST486_STATE         State,
     State->BopCallback      = (BopCallback      ? BopCallback      : Fast486BopCallback     );
     State->IntAckCallback   = (IntAckCallback   ? IntAckCallback   : Fast486IntAckCallback  );
 
+    /* Set the TLB (if given) */
+    State->Tlb = Tlb;
+
     /* Reset the CPU */
     Fast486Reset(State);
 }
@@ -231,6 +235,7 @@ Fast486Reset(PFAST486_STATE State)
     FAST486_IDLE_PROC      IdleCallback     = State->IdleCallback;
     FAST486_BOP_PROC       BopCallback      = State->BopCallback;
     FAST486_INT_ACK_PROC   IntAckCallback   = State->IntAckCallback;
+    PULONG                 Tlb              = State->Tlb;
 
     /* Clear the entire structure */
     RtlZeroMemory(State, sizeof(*State));
@@ -266,7 +271,7 @@ Fast486Reset(PFAST486_STATE State)
     /* Initialize CR0 */
     State->ControlRegisters[FAST486_REG_CR0] |= FAST486_CR0_ET;
 
-    /* Restore the callbacks */
+    /* Restore the callbacks and TLB */
     State->MemReadCallback  = MemReadCallback;
     State->MemWriteCallback = MemWriteCallback;
     State->IoReadCallback   = IoReadCallback;
@@ -274,6 +279,7 @@ Fast486Reset(PFAST486_STATE State)
     State->IdleCallback     = IdleCallback;
     State->BopCallback      = BopCallback;
     State->IntAckCallback   = IntAckCallback;
+    State->Tlb              = Tlb;
 }
 
 VOID
index 94e0f0a..ace7b72 100644 (file)
@@ -296,7 +296,8 @@ BOOLEAN EmulatorInitialize(VOID)
                       EmulatorWriteIo,
                       NULL,
                       EmulatorBiosOperation,
-                      EmulatorIntAcknowledge);
+                      EmulatorIntAcknowledge,
+                      NULL /* TODO: Use a TLB */);
 
     /* Enable interrupts */
     EmulatorSetFlag(EMULATOR_FLAG_IF);